package com.uinnova.product.eam.service.impl;

import com.alibaba.fastjson.JSON;
import com.binary.core.exception.BinaryException;
import com.binary.core.exception.MessageException;
import com.binary.core.util.BinaryUtils;
import com.binary.framework.exception.ServiceException;
import com.binary.jdbc.Page;
import com.google.common.collect.Maps;
import com.uinnova.product.eam.base.util.EamUtil;
import com.uinnova.product.eam.comm.model.es.*;
import com.uinnova.product.eam.model.EamCategoryCdt;
import com.uinnova.product.eam.model.cj.domain.PlanDesignInstance;
import com.uinnova.product.eam.model.cj.vo.DlvrTemplateVO;
import com.uinnova.product.eam.model.cj.vo.PlanDesignInstanceVO;
import com.uinnova.product.eam.model.constants.Constants;
import com.uinnova.product.eam.model.dto.EamCategoryDTO;
import com.uinnova.product.eam.model.enums.AssetType;
import com.uinnova.product.eam.model.enums.CategoryTypeEnum;
import com.uinnova.product.eam.model.enums.OperatorType;
import com.uinnova.product.eam.service.*;
import com.uinnova.product.eam.service.cj.dao.PlanDesignInstanceDao;
import com.uinnova.product.eam.service.cj.service.DeliverableTemplateService;
import com.uinnova.product.eam.service.cj.service.PlanDesignInstanceService;
import com.uinnova.product.eam.service.es.AssetWarehouseDirDao;
import com.uinnova.product.eam.service.es.EamCategoryDesignDao;
import com.uinnova.product.eam.service.es.EamCategoryPrivateDao;
import com.uinnova.product.eam.service.exception.BusinessException;
import com.uinnova.project.api.diagram.v2.client.ESDiagramApiClient;
import com.uinnova.project.base.diagram.comm.model.ESDiagram;
import com.uino.api.client.permission.IRoleApiSvc;
import com.uino.api.client.permission.IUserApiSvc;
import com.uino.bean.cmdb.base.ESCIInfo;
import com.uino.bean.cmdb.base.LibType;
import com.uino.bean.permission.base.SysModule;
import com.uino.bean.permission.base.SysRole;
import com.uino.bean.permission.base.SysUser;
import com.uino.bean.permission.base.TypeVo;
import com.uino.bean.permission.business.UserInfo;
import com.uino.dao.AbstractESBaseDao;
import com.uino.dao.permission.rlt.ESRoleModuleRltSvc;
import com.uino.dao.util.ESUtil;
import com.uino.util.sys.SysUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 资产仓库目录&文件夹数据层实现
 * @author ch
 */
@Service
@Slf4j
public class EamCategorySvcImpl implements EamCategorySvc {

    private static final String OWNER_CODE = "ownerCode.keyword";
    private static final String ADMIN_LOGIN_CODE = "admin";

    @Resource
    private EamCategoryPrivateDao categoryPrivateDao;
    @Resource
    private EamCategoryDesignDao categoryDesignDao;
    @Resource
    private ESDiagramApiClient diagramApiClient;
    @Autowired
    private IFolderPermissionManagerService folderPermissionManagerService;
    @Autowired
    private IUserApiSvc userApiSvc;
    @Autowired
    private IVersionTagSvc versionTagSvc;
    @Autowired
    private PlanDesignInstanceService planDesignInstanceService;
    @Autowired
    private DeliverableTemplateService deliverableTemplateService;

    @Autowired
    private PlanDesignInstanceDao planDao;
    @Autowired
    private ICISwitchSvc ciSwitchSvc;
    @Resource
    private IBmMultiModelHierarchySvc modelHierarchySvc;
    @Autowired
    private ESRoleModuleRltSvc rmRltSvc;
    @Autowired
    private IRoleApiSvc iRoleApiSvc;
    @Autowired
    private IEamArtifactColumnSvc artifactColumnSvc;
    @Autowired
    private EamDiagramRelationSysService diagramRelationSysService;

    @Resource
    AssetWarehouseDirSvc assetWarehouseDirSvc;

    @Resource
    AssetWarehouseDirDao assetWarehouseDirDao;

    @Override
    public EamCategory getById(Long id, LibType libType) {
        if (BinaryUtils.isEmpty(id)) {
            return null;
        }
        if(LibType.PRIVATE.equals(libType) && id.equals(0L)){
            return null;
        }
        return getDao(libType).getById(id);
    }

    @Override
    public EamCategory getByName(String name, Long rootId, String ownerCode, LibType libType) {
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.termQuery("dirName.keyword", name));
        if(LibType.PRIVATE.equals(libType) && !BinaryUtils.isEmpty(ownerCode)){
            boolQuery.must(QueryBuilders.termQuery(OWNER_CODE, ownerCode));
        }
        if(LibType.DESIGN.equals(libType)){
            boolQuery.must(QueryBuilders.wildcardQuery("dirPath.keyword", "*#" + rootId + "#*"));
        }
        return getDao(libType).selectOne(boolQuery);
    }

    @Override
    public EamCategory getModelRoot(Long modelId, String ownerCode, LibType libType) {
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.termQuery("modelId", modelId));
        boolQuery.must(QueryBuilders.termQuery("type", CategoryTypeEnum.MODEL_ROOT.val()));
        if(LibType.PRIVATE.equals(libType) && !BinaryUtils.isEmpty(ownerCode)){
            boolQuery.must(QueryBuilders.termQuery(OWNER_CODE, ownerCode));
        }
        return getDao(libType).selectOne(boolQuery);
    }

    @Override
    public EamCategory getModelByCiCode(Long modelId, String ciCode, String ownerCode, LibType libType) {
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.termQuery("modelId", modelId));
        boolQuery.must(QueryBuilders.termQuery("ciCode.keyword", ciCode));
        boolQuery.must(QueryBuilders.termQuery("type", CategoryTypeEnum.MODEL.val()));
        if(LibType.PRIVATE.equals(libType)  && !BinaryUtils.isEmpty(ownerCode)){
            boolQuery.must(QueryBuilders.termQuery(OWNER_CODE, ownerCode));
        }
        return getDao(libType).selectOne(boolQuery);
    }

    @Override
    public Long getModelIdByDiagram(String diagramId, LibType libType){
        Integer isOpen = LibType.PRIVATE.equals(libType)?0:1;
        ESDiagram diagram = diagramApiClient.getEsDiagram(diagramId, isOpen);
        if(BinaryUtils.isEmpty(diagram)){
            return null;
        }
        EamCategory category = getById(diagram.getDirId(), libType);
        if(BinaryUtils.isEmpty(category)){
            return null;
        }
        return category.getModelId();
    }

    @Override
    public Long saveOrUpdate(EamCategory vo, LibType libType) {
        EamCategory category = null;
        SysUser loginUser = SysUtil.getCurrentUserInfo();
        if(vo.getId()!=null){
            category = getById(vo.getId(), libType);
        }
        Assert.notNull(vo.getDirName(), "dirName");
        if(category == null){
            Assert.notNull(vo.getParentId(), "父文件夹id不可为空!");
            category = new EamCategory();
            if(vo.getId() != null){
                category.setId(vo.getId());
            }else{
                category.setId(ESUtil.getUUID());
            }
            category.setParentId(vo.getParentId());
            category.setDataStatus(1);
            category.setDomainId(loginUser.getDomainId());
            if(vo.getType() == null){
                category.setType(CategoryTypeEnum.UNIVERSAL.val());
            }else{
                category.setType(vo.getType());
            }
            if(vo.getParentId() == 0L){
                category.setDirPath("#" + category.getId() + "#");
                category.setDirLvl(1);
            }else{
                EamCategory parent = getById(vo.getParentId(), libType);
                if (parent.getType()!=CategoryTypeEnum.MODEL.val() && parent.getDirLvl() >= 10) {
                    throw new MessageException("创建失败,文件夹层级超过十级!");
                }
                if((parent.getType().equals(CategoryTypeEnum.MODEL_ROOT.val()) || parent.getType().equals(CategoryTypeEnum.MODEL.val())) &&
                        !category.getType().equals(CategoryTypeEnum.MODEL.val())){
                    throw new MessageException("创建失败,无法在模型目录下创建其它类型文件夹!");
                }
                category.setDirPath(parent.getDirPath() + category.getId() + "#");
                category.setDirLvl(parent.getDirLvl()+1);
            }
            category.setOwnerCode(loginUser.getLoginCode());
            category.setModelId(vo.getModelId());
            category.setCiCode(vo.getCiCode());
            category.setDiagramId(vo.getDiagramId());
            category.setCreator(loginUser.getLoginCode());
            //新建文件夹维护权限
            if (libType == LibType.DESIGN) {
                this.saveFolderPermission(category);
            }
        }
        Long rootId = null;
        if(vo.getParentId() != 0L){
            rootId = Long.parseLong(category.getDirPath().split("#")[1]);
        }
        /*EamCategory eamCategory = getByName(vo.getDirName(), rootId, loginUser.getLoginCode(), libType);
        if(eamCategory != null && category.getType()!=CategoryTypeEnum.MODEL_ROOT.val() && category.getType()!=CategoryTypeEnum.MODEL.val() && !eamCategory.getId().equals(category.getId())){
            throw new MessageException("【"+vo.getDirName()+"】文件夹已存在!");
        }*/
        if(!BinaryUtils.isEmpty(vo.getDirName())){
            category.setDirName(vo.getDirName());
        }
        category.setDiagramId(vo.getDiagramId());
        category.setModifier(loginUser.getLoginCode());
        return getDao(libType).saveOrUpdate(category);
    }

    @Override
    public void saveFolderPermission(EamCategory category) {
        EamCategory designCategory = this.getById(category.getId(), LibType.DESIGN);
        //只考虑新增目录时权限维护
        if (designCategory != null) {
            return;
        }
        //跳过根目录下的文件夹创建--能在根目录下创建文件夹的只有admin角色用户
        if (category.getType() == CategoryTypeEnum.ROOT.val()) {
            return;
        }
        //模型文件夹不做权限控制，只看模型根文件夹--迭代33会带上这个功能
        if (category.getType() == CategoryTypeEnum.MODEL.val()) {
            return;
        }
        // 新增文件夹成功后执行文件夹权限的继承
        //获取父文件需要继承的权限的用户
        List<FolderPermissionManager> folderPermissionManagers = folderPermissionManagerService
                .getNeedExtendFolderPermissionsByDirId(category.getParentId());
        for (FolderPermissionManager folderPermissionManager : folderPermissionManagers) {
            folderPermissionManager.setExtendPermission(Boolean.TRUE);
            folderPermissionManager.setDirId(category.getId());
            folderPermissionManager.setId(ESUtil.getUUID());
            folderPermissionManagerService.setFolderPermissionIfNeed(category, folderPermissionManager);
        }
        if (!CollectionUtils.isEmpty(folderPermissionManagers)) {
            folderPermissionManagerService.saveFolderPermissions(folderPermissionManagers);
        }
    }

    @Override
    public Long createTopCategory(SysModule sysModule) {
        long id = Long.parseLong(String.valueOf(("QUICK_EA"+sysModule.getModuleName()).hashCode() & Integer.MAX_VALUE));
        EamCategory topCategory = getById(id, LibType.DESIGN);
        if(!BinaryUtils.isEmpty(topCategory)){
            return id;
        }
        EamCategory category = new EamCategory();
        category.setId(id);
        category.setParentId(0L);
        category.setType(CategoryTypeEnum.ROOT.val());
        category.setDirName(sysModule.getLabel());
        saveOrUpdate(category, LibType.DESIGN);
        return id;
    }

    @Override
    public void createTopCategoryByAssetDir(List<AssetWarehouseDir> dirList) {
        if (CollectionUtils.isEmpty(dirList)) {
            return;
        }
        HashMap<Long, String> categoryIdMap = new HashMap<>();
        for (AssetWarehouseDir assetWarehouseDir : dirList) {
            Long id = null;
            try {
                id = Long.valueOf(assetWarehouseDir.getModuleUrl().split("=")[1]);
            } catch (NumberFormatException e) {
                log.error("顶级目录字符处理错误：   "+assetWarehouseDir.getModuleUrl());
            }
            categoryIdMap.put(id, assetWarehouseDir.getName());
        }
        List<EamCategory> list = getDao(LibType.DESIGN).getListByQuery(QueryBuilders.termsQuery("id", categoryIdMap.keySet()));
        Map<Long, String> categoryMap = Collections.emptyMap();
        if (!CollectionUtils.isEmpty(list)) {
           categoryMap = list.stream().collect(Collectors.toMap(EamCategory::getId, EamCategory::getDirName, (k1, K2) -> k1));

        }
        Iterator<Map.Entry<Long, String>> iterator = categoryIdMap.entrySet().iterator();
        ArrayList<EamCategory> addEamCategories = new ArrayList<>();
        while (iterator.hasNext()) {
            Map.Entry<Long, String> next = iterator.next();
            if (!categoryMap.containsKey(next.getKey()) || !next.getValue().equals(categoryMap.get(next.getKey()))) {
                EamCategory category = new EamCategory();
                category.setId(next.getKey());
                category.setParentId(0L);
                category.setType(CategoryTypeEnum.ROOT.val());
                category.setDirName(next.getValue());
                category.setDataStatus(1);
                category.setDirPath("#" + category.getId() + "#");
                category.setDirLvl(1);
                addEamCategories.add(category);
            }
        }
        if (!CollectionUtils.isEmpty(addEamCategories)) {
            saveOrUpdateList(addEamCategories, LibType.DESIGN);
        }
    }

    @Override
    public Map<Long, List<EamCategory>> queryChildrenDirsByParentIds(List<Long> categoryIdList, LibType libType) {
        List<EamCategory> listByQuery = getDao(libType).getListByQuery(QueryBuilders.termsQuery("parentId", categoryIdList));
        if (!CollectionUtils.isEmpty(listByQuery)) {
           return listByQuery.stream().collect(Collectors.groupingBy(EamCategory::getParentId));
        }
        return null;
    }

    @Override
    public String getDirPathName(Long dirId, LibType libType) {
        EamCategory category = this.getById(dirId, libType);
        if(category == null || BinaryUtils.isEmpty(category.getDirPath()) || category.getDataStatus() == 0){
            return null;
        }
        //获取路径全名
        List<Long> dirIds = Arrays.stream(category.getDirPath().split("#")).filter(e->!BinaryUtils.isEmpty(e)).map(Long::parseLong).collect(Collectors.toList());
        List<EamCategory> dirList = this.getByIds(dirIds, libType);
        Map<Long, String> dirMap = dirList.stream().collect(Collectors.toMap(EamCategory::getId, EamCategory::getDirName, (k1, k2) -> k2));
        String echoName = dirIds.stream().map(dirMap::get).collect(Collectors.joining("/"));
        return LibType.PRIVATE.equals(libType)?echoName:dirMap.get(dirIds.get(0)) + "/" + echoName;
    }

    @Override
    public Map<Long, String> getDirPathName(List<Long> dirIds, LibType libType) {
        List<EamCategory> categoryList = this.getByIds(dirIds, libType);
        Map<Long, String> result = new HashMap<>();
        if(CollectionUtils.isEmpty(categoryList)){
            return result;
        }
        List<Long> pathDirIds = new ArrayList<>();
        Map<Long, List<Long>> dirPathIdMap = new HashMap<>();
        for (EamCategory each : categoryList) {
            if(BinaryUtils.isEmpty(each.getDirPath())){
                continue;
            }
            List<Long> pathIds = Arrays.stream(each.getDirPath().split("#")).filter(e->!BinaryUtils.isEmpty(e)).map(Long::parseLong).collect(Collectors.toList());
            pathDirIds.addAll(pathIds);
            dirPathIdMap.put(each.getId(), pathIds);
        }
        if(CollectionUtils.isEmpty(pathDirIds)){
            return result;
        }
        List<EamCategory> dirList = this.getByIds(pathDirIds, libType);
        Map<Long, String> dirMap = dirList.stream().collect(Collectors.toMap(EamCategory::getId, EamCategory::getDirName, (k1, k2) -> k2));
        for (Map.Entry<Long, List<Long>> entry : dirPathIdMap.entrySet()) {
            List<Long> eachPath = entry.getValue();
            String echoName = eachPath.stream().map(dirMap::get).collect(Collectors.joining("/"));
            String pathName = LibType.PRIVATE.equals(libType) ? echoName : dirMap.get(eachPath.get(0)) + "/" + echoName;
            result.put(entry.getKey(), pathName);
        }
        return result;
    }

    @Override
    public List<Long> deleteById(Long id, int delType, LibType libType) {
        EamCategory category = getById(id, libType);
        if(category == null){
            return Collections.emptyList();
        }
        String loginCode = SysUtil.getCurrentUserInfo().getLoginCode();
        Integer type = category.getType();
        if(type.equals(CategoryTypeEnum.ROOT.val())){
            throw new ServiceException("无法删除根目录!");
        }
        //1.获取所有子级目录
        List<EamCategory> categoryList = queryByRootId(category.getId(), 1, category.getOwnerCode(), libType);
        List<Long> ids = categoryList.stream().map(EamCategory::getId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        categoryList.sort(Comparator.comparing(EamCategory::getDirLvl));
        //2.如果是模型目录，直接做物理删除，资产库目录，直接做物理删除，否则做判断
        if(category.getType().equals(CategoryTypeEnum.MODEL.val()) || LibType.DESIGN.equals(libType) || delType == Constants.DELETE_PHYSICAL){
            getDao(libType).deleteByIds(ids);
        }else{
            Map<Long, EamCategory> categoryMap = new HashMap<>();
            for (EamCategory each : categoryList) {
                each.setOldParentId(each.getParentId());
                each.setDataStatus(0);
                if(each.getId().equals(category.getId())){
                    //当前删除的目录父级id置为回收站id
                    each.setParentId(0L);
                    each.setDirLvl(1);
                    each.setDirPath("#"+each.getId()+"#");
                }else{
                    EamCategory parent = categoryMap.get(each.getParentId());
                    each.setDirLvl(parent.getDirLvl() + 1);
                    each.setDirPath(parent.getDirPath() + each.getId() + "#");
                }
                categoryMap.put(each.getId(), each);
            }
            getDao(libType).saveOrUpdateBatch(categoryList);
        }
        return ids;
    }

    @Override
    public List<Long> deleteBatch(List<Long> ids, int delType, LibType libType) {
        Assert.notNull(ids, "文件夹id不可为空!");
        String loginCode = SysUtil.getCurrentUserInfo().getLoginCode();
        EamCategory category = getById(ids.get(0), libType);
        List<EamCategory> categoryList = queryByBatchId(ids, 1, loginCode, libType);
        if(CollectionUtils.isEmpty(categoryList) || category == null){
            return Collections.emptyList();
        }
        categoryList.sort(Comparator.comparing(EamCategory::getDirLvl));
        List<Long> result = new ArrayList<>();
        Map<Long, EamCategory> categoryMap = new HashMap<>();
        List<Long> delIds = new ArrayList<>();
        List<EamCategory> updateList = new ArrayList<>();
        EamCategory modelRoot = null;
        if(!BinaryUtils.isEmpty(category.getModelId())){
            modelRoot = this.getModelRoot(category.getModelId(), loginCode, libType);
        }
        for (EamCategory each : categoryList) {
            if(category.getType().equals(CategoryTypeEnum.MODEL.val()) && modelRoot!=null && each.getParentId().equals(modelRoot.getId())){
                // 传 null 异常 无法更新
                each.setDiagramId("");
                updateList.add(each);
            }else if((category.getType().equals(CategoryTypeEnum.MODEL.val())) || LibType.DESIGN.equals(libType) || delType == Constants.DELETE_PHYSICAL){
                delIds.add(each.getId());
            }else{
                each.setOldParentId(each.getParentId());
                each.setDataStatus(0);
                if(ids.contains(each.getId())){
                    //当前删除的目录父级id置为回收站id
                    each.setParentId(0L);
                    each.setDirLvl(1);
                    each.setDirPath("#"+each.getId()+"#");
                }else{
                    EamCategory parent = categoryMap.get(each.getParentId());
                    Assert.notNull(parent, "文件夹数据错误!");
                    each.setDirLvl(parent.getDirLvl() + 1);
                    each.setDirPath(parent.getDirPath() + each.getId() + "#");
                }
                updateList.add(each);
            }
            result.add(each.getId());
            categoryMap.put(each.getId(), each);
        }
        if(!CollectionUtils.isEmpty(delIds)){
            getDao(libType).deleteByIds(delIds);
            if (libType == LibType.DESIGN) {
                //同步删除目录权限
                folderPermissionManagerService.deleteFolderPermissionsByDirIds(delIds);
            }
        }
        if(!CollectionUtils.isEmpty(updateList)){
            getDao(libType).saveOrUpdateBatch(updateList);
        }
        return result;
    }

    @Override
    public List<EamCategoryDTO> queryList(LibType libType, Long rootId) {
        List<EamCategory> categories = libType == LibType.PRIVATE ?
                this.queryPrivateList(rootId, null) :
                this.queryDesignPermissionList(Stream.of(rootId).collect(Collectors.toList()), SysUtil.getCurrentUserInfo().getLoginCode());
        List<EamCategoryDTO> categoryDTOS = new ArrayList<>();
        if (CollectionUtils.isEmpty(categories)) {
            return categoryDTOS;
        }
        //历史版本标签
        Map<Long, List<EamVersionTag>> versionTagMap = new HashMap<>();
        //目录权限
        Map<Long, FolderPermissionManager> folderPermissionMap = new HashMap<>();
        FolderPermissionManager adminFolderPermission = this.getBaseAdminFolderPermission();
        UserInfo user = userApiSvc.getUserInfoByLoginCode(SysUtil.getCurrentUserInfo().getLoginCode());
        List<SysRole> adminRoles = user.getRoles().stream().filter(role -> "admin".equals(role.getRoleName())).collect(Collectors.toList());
        boolean isAdmin = !CollectionUtils.isEmpty(adminRoles);
        if(LibType.DESIGN.equals(libType)){
            Set<Long> modelIds = categories.stream()
                    .filter(category -> category.getType().equals(CategoryTypeEnum.MODEL_ROOT.val()))
                    .map(EamCategory::getModelId).collect(Collectors.toSet());
            if (!CollectionUtils.isEmpty(modelIds)) {
                versionTagMap = versionTagSvc.getVersionTagMapByBranchId(modelIds);
            }
            if (!isAdmin) {
                folderPermissionMap = this.getFolderPermissionByRoles(user.getRoles());
            }
        }
        //查询数据模型
        Map<Long, EamMultiModelHierarchy> dataModel = modelHierarchySvc.getDataModel();
        for (EamCategory category : categories) {
            EamCategoryDTO categoryDTO = new EamCategoryDTO();
            BeanUtils.copyProperties(category, categoryDTO);
            if (LibType.DESIGN.equals(libType)) {
                //设置目录权限
                this.setFolderPermission(isAdmin, folderPermissionMap, adminFolderPermission, categoryDTO);
                if (category.getType().equals(CategoryTypeEnum.MODEL_ROOT.val())) {
                    categoryDTO.setHistoryList(versionTagMap.get(category.getModelId()));
                }
            }else{
                boolean flag = (category.getType().equals(CategoryTypeEnum.MODEL.val()) || category.getType().equals(CategoryTypeEnum.MODEL_ROOT.val()))
                        && dataModel.containsKey(category.getModelId());
                categoryDTO.setDataModelFlag(flag);
            }
            boolean isModel = category.getType() == CategoryTypeEnum.MODEL_ROOT.val()
                    || category.getType() == CategoryTypeEnum.MODEL.val();
            AssetType assetType = isModel ? AssetType.MODEL : AssetType.FOLDER;
            categoryDTO.setAssetType(assetType);
            categoryDTOS.add(categoryDTO);
        }
        categoryDTOS.sort(Comparator.comparing(EamCategoryDTO::getCreateTime));
        return categoryDTOS;
    }

    @Override
    public List<EamCategory> queryPrivateList(Long rootId, String like) {
        //查询一级目录
        SysUser sysUser = SysUtil.getCurrentUserInfo();
        String ownerCode = sysUser.getLoginCode();
        BoolQueryBuilder lv1Query = QueryBuilders.boolQuery();
        lv1Query.must(QueryBuilders.termQuery("ownerCode.keyword", ownerCode));
        lv1Query.must(QueryBuilders.termQuery("domainId", sysUser.getDomainId()));
        lv1Query.must(QueryBuilders.termQuery("dataStatus", 1));
        lv1Query.must(QueryBuilders.termQuery("parentId", rootId));
        List<EamCategory> lv1Categories = categoryPrivateDao.getListByQuery(lv1Query);
        if (CollectionUtils.isEmpty(lv1Categories)) {
            return new ArrayList<>();
        }
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("ownerCode.keyword", ownerCode));
        query.must(QueryBuilders.termQuery("domainId", sysUser.getDomainId()));
        query.must(QueryBuilders.termQuery("dataStatus", 1));
        if(!BinaryUtils.isEmpty(like)){
            query.must(QueryBuilders.wildcardQuery("dirName.keyword", "*" + like.trim() + "*"));
        }
        BoolQueryBuilder childWildcardShouldQuery = QueryBuilders.boolQuery();
        for (EamCategory lv1Category : lv1Categories) {
            childWildcardShouldQuery.should(QueryBuilders.wildcardQuery("dirPath.keyword", "*#" + lv1Category.getId() + "#*"));
        }
        query.must(childWildcardShouldQuery);
        return categoryPrivateDao.getListByQuery(query);
    }

    @Override
    public List<EamCategory> queryDesignPermissionList(List<Long> rootIds, String loginCode) {
        if (CollectionUtils.isEmpty(rootIds)){
            return new ArrayList<>();
        }
        UserInfo user = userApiSvc.getUserInfoByLoginCode(loginCode);
        //查询根目录
        BoolQueryBuilder rootQuery = QueryBuilders.boolQuery();
        rootQuery.must(QueryBuilders.termQuery("dataStatus", 1));
        rootQuery.must(QueryBuilders.termsQuery("id", rootIds));
        List<EamCategory> rootCategories = categoryDesignDao.getListByQuery(rootQuery);
        if (CollectionUtils.isEmpty(rootCategories) || rootCategories.size() != rootIds.size()) {
            throw new BinaryException("根目录不存在");
        }
        List<SysRole> adminRoles = user.getRoles().stream().filter(role -> "admin".equals(role.getRoleName())).collect(Collectors.toList());
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("domainId", user.getDomainId()));
        query.must(QueryBuilders.termQuery("dataStatus", 1));
        BoolQueryBuilder rootIdPathQuery = QueryBuilders.boolQuery();
        for (EamCategory rootCategory : rootCategories) {
            rootIdPathQuery.should(QueryBuilders.wildcardQuery("dirPath.keyword", "*#" + rootCategory.getId() + "#*"));
        }
        query.must(rootIdPathQuery);
        //排除顶级目录
        query.mustNot(QueryBuilders.termQuery("type", CategoryTypeEnum.ROOT.val()));
        //非admin
        if (CollectionUtils.isEmpty(adminRoles)) {
            //校验当前用户资产仓库权限
            rootIds.forEach(rootId -> this.checkModuleAuth(user, rootId));
            query.must(this.getPermissQueryCaseUnAdmin(user, rootIds));
        }
        List<EamCategory> categories = categoryDesignDao.getListByQuery(query);
        //加入当前顶级目录
        categories.addAll(rootCategories);
        return categories;
    }

    /**
     * 非admin权限获取权限目录查询条件
     * @param user
     * @return
     */
    private BoolQueryBuilder getPermissQueryCaseUnAdmin(UserInfo user, List<Long> parentIds) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        //当前用户目录权限
        List<FolderPermissionManager> folderPermissions = folderPermissionManagerService.
                getFolderPermissionByRoleIds(user.getRoles().stream().map(SysRole::getId).collect(Collectors.toSet()));
        List<Long> dirIds = folderPermissions.stream().map(FolderPermissionManager::getDirId).distinct().collect(Collectors.toList());
        if (CollectionUtils.isEmpty(dirIds)) {
            query.must(QueryBuilders.termQuery("id", -1L));
            return query;
        }
        //维护上级目录查询条件
        BoolQueryBuilder modelParentShouldQuery = QueryBuilders.boolQuery();
        for (Long parentId : parentIds) {
            modelParentShouldQuery.should(QueryBuilders.wildcardQuery("dirPath.keyword", "*#" + parentId + "#*"));
        }

        //2.模型根文件夹or普通文件夹-带目录权限
        BoolQueryBuilder folderPermissionQuery = QueryBuilders.boolQuery();
        folderPermissionQuery.mustNot(QueryBuilders.termQuery("type", CategoryTypeEnum.MODEL.val()));
        folderPermissionQuery.must(QueryBuilders.termsQuery("id", dirIds));
        folderPermissionQuery.must(QueryBuilders.termQuery("dataStatus", 1));
        folderPermissionQuery.must(modelParentShouldQuery);
        query.should(folderPermissionQuery);

        //3.加入模型文件夹
        //3.1查模型根目录
        BoolQueryBuilder modelRootQuery = QueryBuilders.boolQuery();
        modelRootQuery.must(QueryBuilders.termQuery("type", CategoryTypeEnum.MODEL_ROOT.val()));
        modelRootQuery.must(QueryBuilders.termQuery("dataStatus", 1));
        modelRootQuery.must(QueryBuilders.termsQuery("id", dirIds));
        modelRootQuery.must(modelParentShouldQuery);
        List<EamCategory> modelRoots = categoryDesignDao.getListByQuery(modelRootQuery);
        //3.2加入模型文件夹
        if (!CollectionUtils.isEmpty(modelRoots)) {
            BoolQueryBuilder modelQuery = QueryBuilders.boolQuery();
            modelQuery.must(QueryBuilders.termsQuery("modelId", modelRoots.stream().map(EamCategory::getModelId).collect(Collectors.toSet())));
            query.should(modelQuery);
        }
        return query;
    }

    /**
     * 校验当前用户资产仓库权限
     * @param user
     * @param rootId
     */
    private void checkModuleAuth(UserInfo user, Long rootId) {
        List<AssetWarehouseDir> warehouseDirs = assetWarehouseDirSvc.getListByRoleIds(user.getRoles().stream().map(SysRole::getId).collect(Collectors.toList()));
        boolean hasAuth = false;
        for (AssetWarehouseDir sysModule : warehouseDirs) {
            if (sysModule.getModuleType() != 3 || StringUtils.isBlank(sysModule.getModuleUrl())) {
                continue;
            }
            if (sysModule.getModuleUrl().contains(rootId.toString())) {
                hasAuth = true;
                break;
            }
        }
        if (!hasAuth) {
            throw new BinaryException("暂无权限");
        }
    }

    @Override
    public List<EamCategory> queryByRootId(Long rootId, Integer status, String ownerCode, LibType libType) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("domainId", SysUtil.getCurrentUserInfo().getDomainId()));
        if(status != null){
            query.must(QueryBuilders.termQuery("dataStatus", status));
        }
        if(LibType.PRIVATE.equals(libType) && !BinaryUtils.isEmpty(ownerCode)){
            query.must(QueryBuilders.termQuery("ownerCode.keyword", ownerCode));
        }
        if(LibType.PRIVATE.equals(libType) && rootId == 0L){
            List<EamCategory> lv1Categories = selectByParentId(rootId, ownerCode, libType);
            if (CollectionUtils.isEmpty(lv1Categories)) {
                return Collections.emptyList();
            }
            BoolQueryBuilder childWildcardShouldQuery = QueryBuilders.boolQuery();
            for (EamCategory lv1Category : lv1Categories) {
                childWildcardShouldQuery.should(QueryBuilders.wildcardQuery("dirPath.keyword", "*#" + lv1Category.getId() + "#*"));
            }
            query.must(childWildcardShouldQuery);
        } else {
            query.must(QueryBuilders.wildcardQuery("dirPath.keyword", "*#" + rootId + "#*"));
        }
        List<EamCategory> categoryList = getDao(libType).getListByQuery(query);
        if(CollectionUtils.isEmpty(categoryList)){
            return Collections.emptyList();
        }
        return categoryList;
    }

    public List<EamCategory> queryByBatchId(List<Long> rootIds, Integer status, String ownerCode, LibType libType) {
        List<EamCategory> categoryList = getByIds(rootIds, libType);
        if (CollectionUtils.isEmpty(categoryList)) {
            return Collections.emptyList();
        }
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("domainId", SysUtil.getCurrentUserInfo().getDomainId()));
        if(status != null){
            query.must(QueryBuilders.termQuery("dataStatus", status));
        }
        if(LibType.PRIVATE.equals(libType) && !BinaryUtils.isEmpty(ownerCode)){
            query.must(QueryBuilders.termQuery("ownerCode.keyword", ownerCode));
        }
        BoolQueryBuilder wildcardQuery = QueryBuilders.boolQuery();
        categoryList.forEach(each -> wildcardQuery.should(QueryBuilders.wildcardQuery("dirPath.keyword", "*#" + each.getId() + "#*")));
        query.must(wildcardQuery);
        List<EamCategory> result = getDao(libType).getListByQuery(query);
        if(CollectionUtils.isEmpty(result)){
            return Collections.emptyList();
        }
        return result;
    }

    @Override
    public List<EamCategoryDTO> queryListByParentId(Long parentId, String like, Boolean auth, LibType libType) {
        SysUser sysUser = SysUtil.getCurrentUserInfo();
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        if(LibType.PRIVATE.equals(libType)){
            query.must(QueryBuilders.termQuery("ownerCode.keyword", sysUser.getLoginCode()));
        }
        query.must(QueryBuilders.termQuery("domainId", sysUser.getDomainId()));
        query.must(QueryBuilders.termQuery("dataStatus", 1));
        if(BinaryUtils.isEmpty(like)){
            query.must(QueryBuilders.termQuery("parentId", parentId));
        }else{
            //按名称模糊搜索时匹配所有级联子级文件夹
            query.must(QueryBuilders.wildcardQuery("dirName.keyword", "*" + like.trim() + "*"));
            query.must(QueryBuilders.wildcardQuery("dirPath.keyword", "*#" + parentId + "#*"));
        }
        List<EamCategory> categoryList = getDao(libType).getListByQuery(query);
        if(CollectionUtils.isEmpty(categoryList)){
            return Collections.emptyList();
        }
        List<EamCategoryDTO> result = new ArrayList<>();
        if(LibType.DESIGN.equals(libType) && auth){
            //目录权限
            Map<Long, FolderPermissionManager> permissionMap = new HashMap<>();
            FolderPermissionManager baseAdminFolderPermission = this.getBaseAdminFolderPermission();
            UserInfo user = userApiSvc.getUserInfoByLoginCode(SysUtil.getCurrentUserInfo().getLoginCode());
            List<SysRole> adminRoles = user.getRoles().stream().filter(role -> "admin".equals(role.getRoleName())).collect(Collectors.toList());
            boolean isAdmin = !CollectionUtils.isEmpty(adminRoles);
            if (!isAdmin) {
                //非admin权限获取权限目录查询条件
                query.must(this.getPermissQueryCaseUnAdmin(user, Stream.of(parentId).collect(Collectors.toList())));
                categoryList = getDao(libType).getListByQuery(query);
                permissionMap = this.getFolderPermissionByRoles(user.getRoles());
            }
            for (EamCategory category : categoryList) {
                EamCategoryDTO categoryDTO = new EamCategoryDTO();
                BeanUtils.copyProperties(category, categoryDTO);
                //设置目录权限
                this.setFolderPermission(isAdmin, permissionMap, baseAdminFolderPermission, categoryDTO);
                result.add(categoryDTO);
            }
        }else{
            result = EamUtil.copy(categoryList, EamCategoryDTO.class);
        }
        result.sort(Comparator.comparing(EamCategoryDTO::getCreateTime));
        return result;
    }

    public EamCategoryDTO getFolderPermission(Long dirId, String userCode) {
        EamCategory category = categoryDesignDao.getById(dirId);
        if(category == null){
            return null;
        }
        EamCategoryDTO result = EamUtil.copy(category, EamCategoryDTO.class);
        //如果是模型文件夹，目录权限通过模型根目录查
        if (category.getType().equals(CategoryTypeEnum.MODEL.val())) {
            //获取模型根目录
            EamCategory root = this.getModelRoot(result.getModelId(), result.getCreator(), LibType.DESIGN);
            result.setId(root.getId());
        }
        //目录权限
        UserInfo user = userApiSvc.getUserInfoByLoginCode(userCode);
        List<SysRole> adminRoles = user.getRoles().stream().filter(role -> "admin".equals(role.getRoleName())).collect(Collectors.toList());
        boolean isAdmin = !CollectionUtils.isEmpty(adminRoles);
        FolderPermissionManager baseAdminPermission = new FolderPermissionManager();
        Map<Long, FolderPermissionManager> permissionMap = new ConcurrentHashMap<>();
        if (isAdmin) {
            baseAdminPermission = this.getBaseAdminFolderPermission();
        } else {
            permissionMap = this.getFolderPermissionByRoles(user.getRoles());
        }
        //权限查询完后(模型权限查询时通过模型根目录id查，查询结果key为modelId，
        //这样模型文件夹可以通过modelId取到模型权限)，如果是模型文件夹，需要将返回的目录id重置回来
        if (category.getType().equals(CategoryTypeEnum.MODEL.val())) {
            result.setId(category.getId());
        }
        //设置目录权限
        this.setFolderPermission(isAdmin, permissionMap, baseAdminPermission, result);
        return result;
    }

    private void setFolderPermission(Boolean isAdmin, Map<Long, FolderPermissionManager> permissionMap
            , FolderPermissionManager baseAdminPermission, EamCategoryDTO categoryDTO) {
        if (isAdmin) {
            FolderPermissionManager adminPermission = this.getAdminFolderPermission(baseAdminPermission, categoryDTO.getId());
            categoryDTO.setFolderPermissionManager(adminPermission);
            return;
        }
        boolean model = categoryDTO.getType().equals(CategoryTypeEnum.MODEL.val())
                || categoryDTO.getType().equals(CategoryTypeEnum.MODEL_ROOT.val());
        FolderPermissionManager permission = model ? permissionMap.get(categoryDTO.getModelId()) : permissionMap.get(categoryDTO.getId());
        if (permission == null) {
            return;
        }
        FolderPermissionManager newPermission = new FolderPermissionManager();
        BeanUtils.copyProperties(permission, newPermission);
        if (model) {
            newPermission.setDirId(categoryDTO.getId());
        }
        categoryDTO.setFolderPermissionManager(newPermission);
    }

    @Override
    public List<EamCategoryDTO> queryRecycleByParentId(Long parentId, String like, LibType libType) {
        SysUser sysUser = SysUtil.getCurrentUserInfo();
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        if(LibType.PRIVATE.equals(libType)){
            query.must(QueryBuilders.termQuery("ownerCode.keyword", sysUser.getLoginCode()));
        }
        query.must(QueryBuilders.termQuery("domainId", sysUser.getDomainId()));
        query.must(QueryBuilders.termQuery("dataStatus", 0));
        if(BinaryUtils.isEmpty(like) || parentId.equals(0L)){
            query.must(QueryBuilders.termQuery("parentId", parentId));
        }else{
            query.must(QueryBuilders.wildcardQuery("dirPath.keyword", "*#" + parentId + "#*"));
        }
        if(!BinaryUtils.isEmpty(like)){
            query.must(QueryBuilders.wildcardQuery("dirName.keyword", "*" + like.trim() + "*"));
        }
        query.mustNot(QueryBuilders.termQuery("type", CategoryTypeEnum.MODEL.val()));
        Page<EamCategory> resultPage = getDao(libType).getSortListByQuery(1, 1000, query, "createTime" , false);
        if(CollectionUtils.isEmpty(resultPage.getData())){
            return Collections.emptyList();
        }
        return EamUtil.copy(resultPage.getData(), EamCategoryDTO.class);
    }

    @Override
    public List<EamCategory> queryByType(Integer type, Long rootId, String ownerCode, LibType libType) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("domainId", SysUtil.getCurrentUserInfo().getDomainId()));
        query.must(QueryBuilders.termQuery("dataStatus", 1));
        if(type != null){
            query.must(QueryBuilders.termQuery("type", type));
        }
        if(LibType.PRIVATE.equals(libType) && !BinaryUtils.isEmpty(ownerCode)){
            query.must(QueryBuilders.termQuery("ownerCode.keyword", ownerCode));
        }
        if(rootId != null){
            query.must(QueryBuilders.wildcardQuery("dirPath.keyword", "*#" + rootId + "#*"));
        }
        List<EamCategory> categoryList = getDao(libType).getListByQuery(query);
        if(CollectionUtils.isEmpty(categoryList)){
            return Collections.emptyList();
        }
        return categoryList;
    }

    @Override
    public List<EamCategory> queryByDiagramId(List<String> diagramId, String ownerCode, LibType libType) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("domainId", SysUtil.getCurrentUserInfo().getDomainId()));
        query.must(QueryBuilders.termQuery("dataStatus", 1));
        query.must(QueryBuilders.termsQuery("diagramId.keyword", diagramId));
        if(LibType.PRIVATE.equals(libType) && !BinaryUtils.isEmpty(ownerCode)){
            query.must(QueryBuilders.termQuery("ownerCode.keyword", ownerCode));
        }
        List<EamCategory> categoryList = getDao(libType).getListByQuery(query);
        if(CollectionUtils.isEmpty(categoryList)){
            return Collections.emptyList();
        }
        return categoryList;
    }

    @Override
    public Integer copyBatch(EamCategoryCdt cdt) {
        List<Long> copyIds = cdt.getDirIds();
        Assert.notNull(copyIds, "文件夹id不能为空!");
        Assert.notNull(cdt.getTargetId(), "目标文件夹id不能为空!");
        List<EamCategory> copyDirList = getByIds(copyIds, cdt.getLibType());
        EamCategory target = getById(cdt.getTargetId(), cdt.getLibType());
        if(!cdt.getTargetId().equals(0L) && (target.getType().equals(CategoryTypeEnum.MODEL_ROOT.val()) || target.getType().equals(CategoryTypeEnum.MODEL.val()))){
            throw new BusinessException("文件夹不能复制至模型目录!");
        }
        List<EamCategory> saveList = new ArrayList<>();
        for (EamCategory each : copyDirList) {
            if(each.getType().equals(CategoryTypeEnum.MODEL_ROOT.val()) || each.getType().equals(CategoryTypeEnum.MODEL.val())){
                throw new BusinessException("无法复制模型目录!");
            }
            each.setId(ESUtil.getUUID());
            if(cdt.getTargetId().equals(0L)){
                each.setParentId(0L);
                each.setDirPath("#" + each.getId() + "#");
                each.setDirLvl(1);
            }else{
                each.setParentId(target.getId());
                each.setDirPath(target.getDirPath() + each.getId() + "#");
                each.setDirLvl(target.getDirLvl() + 1);
            }
            each.setCreateTime(ESUtil.getNumberDateTime());
            each.setModifyTime(ESUtil.getNumberDateTime());
            each.setDirName(each.getDirName());
            saveList.add(each);
        }
        saveOrUpdateList(saveList, cdt.getLibType());
        return getDao(cdt.getLibType()).saveOrUpdateBatch(saveList);
    }

    /**
     * 文件夹内可能有模型树（也是一种文件夹），视图，方案
     *
     */
    @Override
    public Integer moveBatch(EamCategoryCdt cdt) {
        SysUser userInfo = SysUtil.getCurrentUserInfo();
        String loginCode = userInfo.getLoginCode();
        Long targetDirId = cdt.getTargetId();
        List<Long> dirIds = cdt.getDirIds();
        List<String> diagramIds = cdt.getDiagramIds();
        List<Long> planIds = cdt.getPlanIds();
        BinaryUtils.checkEmpty(targetDirId, "目标文件夹id不能为空");
        if (BinaryUtils.isEmpty(dirIds) && BinaryUtils.isEmpty(diagramIds) && BinaryUtils.isEmpty(planIds)) {
            throw new BusinessException("待移动文件夹/方案/视图不能同时为空");
        }
        EamCategory targetDir = getById(targetDirId, cdt.getLibType());
        //模型文件夹不可以移动，在查询时过滤；
        if(!targetDirId.equals(0L) && BinaryUtils.isEmpty(targetDir)){
            throw new BusinessException("目标文件夹不存在");
        }
        //1.移动文件夹；
        if (!BinaryUtils.isEmpty(dirIds)) {
            moveCatalog(cdt, loginCode, targetDir);
        }
        //2.移动的是视图
        if (!BinaryUtils.isEmpty(diagramIds)) {
            moveDiagram(cdt, loginCode, targetDirId, diagramIds);
        }
        //3.移动的是方案
        if (!BinaryUtils.isEmpty(planIds)) {
            movePlan(cdt, loginCode, targetDirId, planIds);
        }
        return 1;
    }

    private void movePlan(EamCategoryCdt cdt, String loginCode, Long targetDirId, List<Long> planIds) {
        BoolQueryBuilder query = new BoolQueryBuilder();
        query.must(QueryBuilders.termQuery("dirId", targetDirId))
                .must(QueryBuilders.termQuery("creatorCode.keyword", loginCode));
        if(cdt.getLibType().equals(LibType.PRIVATE)){
            query.must(QueryBuilders.termQuery("assetsType",Constants.DESIGN));
        }
        if(cdt.getLibType().equals(LibType.DESIGN)){
            query.must(QueryBuilders.termQuery("assetsType",Constants.ASSETS));
        }
        //目标文件夹下的方案
        List<PlanDesignInstance> planListByTargetId = planDao.getListByQuery(query);
        List<String> planNames = null;
        if(!BinaryUtils.isEmpty(planListByTargetId)){
            planNames = planListByTargetId.stream().map(PlanDesignInstance::getName).collect(Collectors.toList());
        }
        //待移动的方案
        List<PlanDesignInstance> planList = planDesignInstanceService.getByIds(planIds);
        if(!BinaryUtils.isEmpty(planList)){
            List<Long> dirIds = planList.stream().map(PlanDesignInstance::getAssetsDirId).distinct().collect(Collectors.toList());
            this.checkOperatorPermission(dirIds, AssetType.SCHEME, loginCode, cdt.getLibType(), OperatorType.MOVE);
            for (PlanDesignInstance plan : planList) {
                if(!BinaryUtils.isEmpty(planNames) && planNames.contains(plan.getName())){
                    throw new BusinessException("目标文件夹下已存在同名方案");
                }
                plan.setDirId(targetDirId);
                plan.setAssetsDirId(targetDirId);
                plan.setCreatorCode(loginCode);
            }
            //看下这里是否需要新定义一个集合，数据有没有存上
            planDao.saveOrUpdateBatch(planList);
        }
    }

    private void moveDiagram(EamCategoryCdt cdt, String loginCode, Long targetDirId, List<String> diagramIds) {
        //获取目标文件夹下的视图信息
        int open = cdt.getLibType() .equals(LibType.DESIGN)?1:0;
        //查询待移动的视图信息，正常是单张视图
        List<ESDiagram> esDiagrams = diagramApiClient.selectByIds(diagramIds, null, Collections.singletonList(open));
        if (BinaryUtils.isEmpty(esDiagrams)) {
            return;
        }
        List<Long> dirIds = esDiagrams.stream().map(ESDiagram::getDirId).distinct().collect(Collectors.toList());
        this.checkOperatorPermission(dirIds, AssetType.DIAGRAM, loginCode, cdt.getLibType(), OperatorType.MOVE);
        for (ESDiagram esDiagram : esDiagrams) {
            Integer diagramSubType = esDiagram.getDiagramSubType();
            if(4 == diagramSubType){
                throw new BinaryException("模型文件夹下的主视图不可移动");
            }
            esDiagram.setDirId(targetDirId);
            esDiagram.setOwnerCode(loginCode);
        }
        //看下这里是否需要新定义一个集合，数据有没有存上
        diagramApiClient.saveOrUpdateBatch(esDiagrams);
    }

    private void moveCatalog(EamCategoryCdt cdt, String loginCode, EamCategory targetDir) {
        List<EamCategory> categoryList = queryByBatchId(cdt.getDirIds(), 1, loginCode, cdt.getLibType());
        categoryList.sort(Comparator.comparing(EamCategory::getDirLvl));
        Map<Long, EamCategory> parentMap = new HashMap<>();
        if(targetDir != null){
            if(targetDir.getType().equals(CategoryTypeEnum.MODEL_ROOT.val()) || targetDir.getType().equals(CategoryTypeEnum.MODEL.val())){
                throw new BinaryException("无法移入模型文件夹,请重新选择!");
            }
            parentMap.put(targetDir.getId(), targetDir);
        }
        //目前资产目录下只有模型文件夹能移动
        this.checkOperatorPermission(cdt.getDirIds(), AssetType.MODEL, loginCode, cdt.getLibType(), OperatorType.MOVE);
        for (EamCategory category : categoryList) {
            int dirLvl;
            String dirPath;
            if(cdt.getDirIds().contains(category.getId())){
                if(targetDir!=null && category.getId().equals(targetDir.getId())){
                    throw new BinaryException("文件无法移动到当前目录,请重新选择!");
                }
                if(targetDir!=null && targetDir.getDirPath().contains(category.getDirPath()) && targetDir.getDirLvl()>category.getDirLvl()){
                    throw new BinaryException("无法移动到子文件夹,请重新选择!");
                }
                category.setParentId(cdt.getTargetId());
                dirLvl = targetDir==null?1:targetDir.getDirLvl()+1;
                dirPath = targetDir==null?"#"+category.getId()+"#":targetDir.getDirPath()+category.getId()+"#";
            }else{
                EamCategory parent = parentMap.get(category.getParentId());
                dirLvl = parent.getDirLvl()+1;
                dirPath = parent.getDirPath()+category.getId()+"#";
            }
            if(category.getType() == CategoryTypeEnum.MODEL_ROOT.val() && dirLvl > 5){
                //模型无法创建在五级以下文件夹内
                throw new MessageException("移动失败,模型无法移动至五级以下文件夹内");
            }else if (dirLvl > 10) {
                throw new MessageException("移动失败,文件夹层级超过十级");
            }
            category.setDirPath(dirPath);
            category.setDirLvl(dirLvl);
            parentMap.put(category.getId(), category);
        }
        getDao(cdt.getLibType()).saveOrUpdateBatch(categoryList);
        //处理下目录权限
        if (LibType.DESIGN.equals(cdt.getLibType()) && targetDir != null) {
            folderPermissionManagerService.moveDirChangeFolderPermissions(cdt.getDirIds(), targetDir.getId());
        }
    }


    @Override
    public Map<String, Object> queryPushPath(Long modelId, String diagramId, Long planId) {
        Map<String, Object> pathInfo = new HashMap<>();
        ESDiagram esDiagram = new ESDiagram();

        String dirPath = "";
        Long dirId = null;
        AssetType type = null;
        String assetId = "";

        if (!BinaryUtils.isEmpty(planId)) {
            type = AssetType.SCHEME;
            assetId = planId.toString();
            // 查询方案的默认位置
            PlanDesignInstanceVO planInfo = planDesignInstanceService.getById(planId);
            String echoDirName = planInfo.getEchoDirName();
            pathInfo.put("pushType", type.assetType);
            if (BinaryUtils.isEmpty(echoDirName)) {
                // 获取方案关联的模板的发布位置
                Long templateId = planInfo.getTemplateId();
                if (BinaryUtils.isEmpty(templateId)) {
                    pathInfo.put("dirId", dirId);
                } else {
                    DlvrTemplateVO dlvrTemplateById = deliverableTemplateService.getDlvrTemplateById(templateId);
                    dirId = dlvrTemplateById.getAssetsDirId();
                    pathInfo.put("dirId", dirId);
                    dirPath = dlvrTemplateById.getEchoDirName();
                }
            } else {
                dirId = planInfo.getAssetsDirId();
                pathInfo.put("dirId", dirId);
                dirPath = echoDirName;
            }
            pathInfo.put("dirNamePath", dirPath);
            return pathInfo;
        }

        if (!BinaryUtils.isEmpty(diagramId)) {
            List<ESDiagram> esDiagrams = diagramApiClient.queryDBDiagramInfoByIds(new String[]{diagramId});
            esDiagram = esDiagrams.get(0);
            Long diagramDirId = esDiagram.getDirId();
            // 根据目录ID获取新表的信息
            EamCategory categoryInfo = this.getById(diagramDirId, LibType.PRIVATE);
            if (!BinaryUtils.isEmpty(categoryInfo) &&
                    !BinaryUtils.isEmpty(categoryInfo.getModelId()) && categoryInfo.getType() != 4) {
                modelId = categoryInfo.getModelId();
            }
        }

        // 查询当前视图或模型位于仓库的位置
        if (!BinaryUtils.isEmpty(modelId)) {
            type = AssetType.MODEL;
            assetId = modelId.toString();
            // 查询模型视图以及模型中的普通视图的发布位置
            pathInfo.put("pushType", type.assetType);
            List<EamCategory> eamCategories = this.selectByModelId(modelId, LibType.DESIGN, null);
            for (EamCategory eamCategory : eamCategories) {
                if (eamCategory.getType() == 4) {
                    // 返回资产仓库模型树根级ID
                    dirId = eamCategory.getParentId();
                    pathInfo.put("dirId", dirId);
                    dirPath = eamCategory.getDirPath();
                }
            }
        } else {
            type = AssetType.DIAGRAM;
            assetId = diagramId;
            // 查询普通视图以及制品视图的发布位置
            pathInfo.put("pushType", type.assetType);
            if (isBindAssert(esDiagram)) {
                //1-》到之前位置
                //2-〉资产实例文件夹
                //3-》自己输入
                String releaseDiagramId = esDiagram.getReleaseDiagramId();
                if (BinaryUtils.isEmpty(releaseDiagramId)) {
                    // 初次发布
                    EamCategory category = getBindAssertDir(esDiagram.getDEnergy());
                    if (category != null) {
                        dirId = category.getId();
                        dirPath = category.getDirPath();
                    }
                    pathInfo.put("dirId", dirId);
                } else {
                    // 获取资产仓库视图的目录ID
                    List<ESDiagram> releaseeDiagrams = diagramApiClient.queryDBDiagramInfoByIds(new String[]{releaseDiagramId});
                    if (CollectionUtils.isEmpty(releaseeDiagrams)) {
                        EamCategory category = getBindAssertDir(esDiagram.getDEnergy());
                        if (category != null) {
                            dirId = category.getId();
                            dirPath = category.getDirPath();
                        }
                        pathInfo.put("dirId", dirId);
                    } else {
                        ESDiagram releaseDiagram = releaseeDiagrams.get(0);
                        dirId = releaseDiagram.getDirId();
                        EamCategory eamCategory = this.getById(dirId, LibType.DESIGN);
                        if (!BinaryUtils.isEmpty(eamCategory)) {
                            dirPath = eamCategory.getDirPath();
                            dirId = releaseDiagram.getDirId();
                        } else {
                            EamCategory category = getBindAssertDir(esDiagram.getDEnergy());
                            if (category != null) {
                                dirId = category.getId();
                                dirPath = category.getDirPath();
                            }
                        }
                        pathInfo.put("dirId", dirId);
                    }
                }
            } else {
                String releaseDiagramId = esDiagram.getReleaseDiagramId();
                if (BinaryUtils.isEmpty(releaseDiagramId)) {
                    // 初次发布
                    pathInfo.put("dirId", dirId);
                } else {
                    // 获取资产仓库视图的目录ID
                    List<ESDiagram> releaseeDiagrams = diagramApiClient.queryDBDiagramInfoByIds(new String[]{releaseDiagramId});
                    if (CollectionUtils.isEmpty(releaseeDiagrams)) {
                        pathInfo.put("dirId", dirId);
                    } else {
                        ESDiagram releaseDiagram = releaseeDiagrams.get(0);
                        dirId = releaseDiagram.getDirId();
                        pathInfo.put("dirId", dirId);
                        EamCategory eamCategory = this.getById(dirId, LibType.DESIGN);
                        if (!BinaryUtils.isEmpty(eamCategory)) {
                            dirPath = eamCategory.getDirPath();
                        }
                    }
                }
            }
        }

        if (BinaryUtils.isEmpty(dirId)) {
            return pathInfo;
        }
        EamCategory designInfo = this.getById(dirId, LibType.DESIGN);
        if(BinaryUtils.isEmpty(designInfo)){
            return pathInfo;
        }
        AssetWarehouseDir sysModule = this.checkDirAuthority(designInfo);
        if (BinaryUtils.isEmpty(sysModule)) {
            return pathInfo;
        }
        if (!BinaryUtils.isEmpty(dirPath)) {
            String[] dirIds = dirPath.split("#");
            List<Long> ids = new ArrayList<>();
            for (String idStr : dirIds) {
                if (!BinaryUtils.isEmpty(idStr)) {
                    ids.add(Long.valueOf(idStr));
                }
            }
            List<EamCategory> designCategory = this.getByIds(ids, LibType.DESIGN);
            StringBuilder dirNamePath = new StringBuilder();
            designCategory = designCategory.stream().sorted(Comparator.comparing(EamCategory::getDirLvl)).collect(Collectors.toList());
            for (EamCategory design : designCategory) {
                dirNamePath.append("/").append(design.getDirName());
            }
            // 获取根目录名称
            pathInfo.put("dirNamePath", sysModule.getName() + dirNamePath);
        }

        boolean flag = this.checkAssetType(sysModule, type, assetId, null);
        if (!flag) {
            throw new BinaryException("当前默认发布位置【" + pathInfo.get("dirNamePath") + "】无权限，请联系管理员");
        }

        return pathInfo;
    }

    private boolean isBindAssert(ESDiagram esDiagram) {
        if (esDiagram.getDiagramSubType() == null
                || esDiagram.getDiagramSubType() != 2
                || StringUtils.isBlank(esDiagram.getViewType())) {
            return false;
        }
        Long artifactId = Long.valueOf(esDiagram.getViewType());
        return !CollectionUtils.isEmpty(artifactColumnSvc.getArchSystemList(artifactId));
    }

    private EamCategory getBindAssertDir(String diagramEnergy) {
        EamDiagramRelationSys diagramRelationSys = diagramRelationSysService.getEamDiagramRelationSys(diagramEnergy);
        if (diagramRelationSys == null) {
            return null;
        }
        return getByCiCode(diagramRelationSys.getEsSysId(), null, LibType.DESIGN);
    }

    @Override
    public EamCategory getByCiCode(String ciCode, String ownerCode, LibType libType) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("ciCode.keyword", ciCode));
        query.must(QueryBuilders.termQuery("type", CategoryTypeEnum.SYSTEM.val()));
        query.must(QueryBuilders.termQuery("dataStatus", 1));
        if (libType.equals(LibType.PRIVATE)) {
            query.must(QueryBuilders.termQuery("ownerCode.keyword", ownerCode));
        }
        List<EamCategory> categories = getDao(libType).getListByQuery(query);
        return CollectionUtils.isEmpty(categories) ? null : categories.get(0);
    }


    @Override
    public List<EamCategory> getByIds(List<Long> ids, LibType libType) {
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.termsQuery("id", ids));
        Page<EamCategory> relPage = getDao(libType).getListByQuery(1,10000, boolQuery);
        return relPage.getData();
    }

    @Override
    public List<EamCategory> selectByModelId(Long modelId, LibType libType, String loginCode) {
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        if(!BinaryUtils.isEmpty(modelId)){
            boolQuery.must(QueryBuilders.termQuery("modelId", modelId));
        }else{
            boolQuery.mustNot(QueryBuilders.existsQuery("modelId"));
        }
        if(libType == LibType.PRIVATE && !BinaryUtils.isEmpty(loginCode)){
            boolQuery.must(QueryBuilders.termQuery(OWNER_CODE, loginCode));
        }
        boolQuery.must(QueryBuilders.termQuery("domainId", SysUtil.getCurrentUserInfo().getDomainId()));
        boolQuery.must(QueryBuilders.termQuery("dataStatus", 1));
        return getDao(libType).getListByQuery(boolQuery);
    }

    @Override
    public List<EamCategory> selectByModelIds(Map<String, List<Long>> userCodeAndModelIdsMap, LibType libType) {
        if (MapUtils.isEmpty(userCodeAndModelIdsMap)) {
            return new ArrayList<>();
        }
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        for (String userCode : userCodeAndModelIdsMap.keySet()) {
            BoolQueryBuilder oneQuery = QueryBuilders.boolQuery();
            if (libType.equals(LibType.PRIVATE)) {
                oneQuery.must(QueryBuilders.termQuery(OWNER_CODE, userCode));
            }
            List<Long> modelIds = userCodeAndModelIdsMap.get(userCode);
            if (CollectionUtils.isEmpty(modelIds)) {
                continue;
            }
            oneQuery.must(QueryBuilders.termsQuery("modelId", modelIds));
            oneQuery.must(QueryBuilders.termQuery("dataStatus", 1));
            boolQuery.should(oneQuery);
        }
        return getDao(libType).getListByQuery(boolQuery);
    }

    @Override
    public List<EamCategory> selectByParentId(Long parentId, String ownerCode, LibType libType) {
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.termQuery("parentId", parentId));
        if(LibType.PRIVATE.equals(libType) && !BinaryUtils.isEmpty(ownerCode)){
            boolQuery.must(QueryBuilders.termQuery(OWNER_CODE, ownerCode));
        }
        boolQuery.must(QueryBuilders.termQuery("domainId", SysUtil.getCurrentUserInfo().getDomainId()));
        boolQuery.must(QueryBuilders.termQuery("dataStatus", 1));
        return getDao(libType).getListByQuery(boolQuery);
    }

    @Override
    public void saveOrUpdateList(List<EamCategory> records, LibType libType) {
        if(BinaryUtils.isEmpty(records)){
            return;
        }
        getDao(libType).saveOrUpdateBatch(records);
    }

    @Override
    public int delByIds(List<Long> ids, LibType libType) {
        if(BinaryUtils.isEmpty(ids)){
            return 0;
        }
        return getDao(libType).deleteByIds(ids);
    }

    @Override
    public Long getModelIdByDiagramIds(List<String> diagramId, LibType libType){
        List<ESDiagram> diagramList = diagramApiClient.selectByIds(diagramId, null, null);
        if(BinaryUtils.isEmpty(diagramList)){
            return null;
        }
        // TODO ownerCode参数
        EamCategory rootCatalog = getById(diagramList.get(0).getDirId(), libType);
        if(BinaryUtils.isEmpty(rootCatalog)){
            return null;
        }
        return rootCatalog.getModelId();
    }

    @Override
    public EamCategory selectByDiagramId(String diagramId, String ownerCode, LibType libType) {
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.termQuery("diagramId.keyword", diagramId));
        if(libType == LibType.PRIVATE && !BinaryUtils.isEmpty(ownerCode)){
            boolQuery.must(QueryBuilders.termQuery(OWNER_CODE, ownerCode));
        }
        Page<EamCategory> parentPage = getDao(libType).getListByQuery(1,1, boolQuery);
        if(CollectionUtils.isEmpty(parentPage.getData())){
            return null;
        }
        return parentPage.getData().get(0);
    }

    @Override
    public List<EamCategory> selectByDiagramIdList(List<String> diagramIds, String ownerCode, LibType libType) {
        if(BinaryUtils.isEmpty(diagramIds)){
            return Collections.emptyList();
        }
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.termsQuery("diagramId.keyword", diagramIds));
        if(libType == LibType.PRIVATE && !BinaryUtils.isEmpty(ownerCode)){
            boolQuery.must(QueryBuilders.termQuery(OWNER_CODE, ownerCode));
        }
        return getDao(libType).selectListByQuery(1,diagramIds.size(), boolQuery);
    }

    @Override
    public EamCategory selectByCiCode(Long modelId, String ciCode, String ownerCode, LibType libType) {
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.termQuery("ciCode.keyword", ciCode));
        if(libType == LibType.PRIVATE){
            boolQuery.must(QueryBuilders.termQuery(OWNER_CODE, ownerCode));
        }
        if(!BinaryUtils.isEmpty(modelId)){
            boolQuery.must(QueryBuilders.termQuery("modelId", modelId));
        } else {
            boolQuery.mustNot(QueryBuilders.existsQuery("modelId"));
        }
        return getDao(libType).selectOne(boolQuery);
    }

    @Override
    public List<EamCategory> selectListByCiCodes(Long modelId, List<String> ciCodes, String ownerCode, LibType libType) {
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        if(LibType.PRIVATE == libType){
            boolQuery.must(QueryBuilders.termQuery(OWNER_CODE, ownerCode));
        }
        if(!BinaryUtils.isEmpty(modelId)){
            boolQuery.must(QueryBuilders.termQuery("modelId", modelId));
        }
        boolQuery.must(QueryBuilders.termsQuery("ciCode.keyword", ciCodes));
        return getDao(libType).getListByQuery(boolQuery);
    }

    @Override
    public void clearDiagramIdByDirId(Long id, String loginCode, LibType libType) {
        String script = "ctx._source.diagramId=null;";
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.termQuery("id", id));
        if (LibType.PRIVATE == libType) {
            boolQuery.must(QueryBuilders.termQuery(OWNER_CODE, loginCode));
        }
        getDao(libType).updateByQuery(boolQuery, script, true);
    }

    /**
     *  根据三库标识返回对应的 DAO
     * @param libType 三库标识
     * @return
     */
    private AbstractESBaseDao<EamCategory, EamCategory> getDao(LibType libType) {
        if (LibType.PRIVATE.equals(libType)) {
            return categoryPrivateDao;
        }
        return categoryDesignDao;
    }

    public AssetWarehouseDir checkDirAuthority(EamCategory designInfo) {
        // 获取传参ID的根目录
        String dirPath = designInfo.getDirPath();
        String[] dirIds = dirPath.split("#");
        Long rootDirId = Long.valueOf(dirIds[1]);
//        EamCategory rootDirInfo = this.getById(rootDirId, LibType.DESIGN);
        List<AssetWarehouseDir> listByQuery = assetWarehouseDirDao.getListByQuery(QueryBuilders.wildcardQuery("moduleUrl.keyword", "*" + rootDirId + "*"));
        if (CollectionUtils.isEmpty(listByQuery)) {
            return null;
        }
        AssetWarehouseDir sysModule = listByQuery.get(0);
        // 判断当前用户角色是否拥有该目录权限
        SysUser currentUserInfo = SysUtil.getCurrentUserInfo();
        UserInfo user = userApiSvc.getUserInfoByLoginCode(currentUserInfo.getLoginCode());
        List<Long> roleList = user.getRoles().stream().map(SysRole::getId).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(sysModule.getRoleIdList()) ||CollectionUtils.isEmpty(roleList)
                || Collections.disjoint(roleList, sysModule.getRoleIdList())) {
            throw new BinaryException("当前用户角色无[" + sysModule.getName() + "]目录的权限");
        }
        return sysModule;
    }

    @Override
    public List<EamCategoryDTO> getPublishedLibrary(AssetType type, String assetId) {
        BinaryUtils.checkNull(type, "资产类型");
        String loginCode = SysUtil.getCurrentUserInfo().getLoginCode();
        if (type == AssetType.TEMPLATE) {
            //交付物模板查所有
            loginCode = ADMIN_LOGIN_CODE;
        } else {
            BinaryUtils.checkNull(assetId, "资产id");
        }
        List<EamCategoryDTO> categoryDTOS = this.queryDesignPermissionRootList(loginCode);
        if (CollectionUtils.isEmpty(categoryDTOS)) {
            return new ArrayList<>();
        }
        //处理下资产类型为视图但是所在目录为模型非根目录(type=5)的情况，此时视图按模型处理
        if (type == AssetType.DIAGRAM) {
            ESDiagram diagram = this.queryDiagram(assetId);
            LibType libType = diagram.getIsOpen() == 0 ? LibType.PRIVATE : LibType.DESIGN;
            EamCategory category = getById(diagram.getDirId(), libType);
            if (category != null && category.getType() == CategoryTypeEnum.MODEL.val()) {
                type = AssetType.MODEL;
                assetId = category.getModelId().toString();
            }
        }
        Long assetTypeId = this.getAssetTypeId(type, assetId);
        List<EamCategoryDTO> results = new ArrayList<>();
        for (EamCategoryDTO categoryDTO : categoryDTOS) {
            if (!this.checkAssetType(categoryDTO.getSysModulel(), type, assetId, assetTypeId)) {
                continue;
            }
            //分库名称取系统菜单的显示名称
            categoryDTO.setDirName(categoryDTO.getSysModulel().getName());
            EamCategoryDTO result = new EamCategoryDTO();
            BeanUtils.copyProperties(categoryDTO, result);
            result.setSysModulel(null);
            results.add(result);
        }
        results.sort(Comparator.comparing(EamCategoryDTO::getCreateTime));
        return results;
    }

    /**
     * 获取资产分库对应菜单
     * @param libraries
     * @param category
     * @return
     */
    public AssetWarehouseDir getSysModule(List<AssetWarehouseDir> libraries, EamCategory category) {
        for (AssetWarehouseDir library : libraries) {
            if (library.getModuleUrl().contains(category.getId().toString())) {
                return library;
            }
        }
        return null;
    }

    /**
     * 校验当前资产仓库菜单是否可以存放当前资产
     * @param library 资产仓库菜单
     * @param type 资产类型
     * @param assetId 资产id
     * @param assetTypeId 资产类型id
     * @return
     */
    private boolean checkAssetType(AssetWarehouseDir library, AssetType type, String assetId, Long assetTypeId) {
        //模板类型不校验（用于交付物模板获取发布资产仓库）
        if (type == AssetType.TEMPLATE) {
            return true;
        }
        List<Integer> assetTypes = library.getAssetType();
        //资产仓库没有勾选资产类型
        if (CollectionUtils.isEmpty(assetTypes)) {
            return false;
        }
        //资产仓库菜单无当前资产类型
        if (!assetTypes.contains(type.assetType)) {
            return false;
        }
        //获取资产类型id
        if (assetTypeId == null) {
            assetTypeId = this.getAssetTypeId(type, assetId);
        }
        Set<Long> templateIds;
        switch (type) {
            case SCHEME:
                templateIds = library.getSchemeList().stream().map(TypeVo::getId).collect(Collectors.toSet());
                return CollectionUtils.isEmpty(templateIds) || templateIds.contains(assetTypeId);
            case DIAGRAM:
                //这里需要注意下：自由视图默认0L
                Set<Long> artifactIds = library.getDiagramList().stream().map(TypeVo::getId).collect(Collectors.toSet());
                return CollectionUtils.isEmpty(artifactIds) || artifactIds.contains(assetTypeId);
            case MODEL:
                Set<Long> modelIds = library.getModelList().stream().map(TypeVo::getId).collect(Collectors.toSet());
                return CollectionUtils.isEmpty(modelIds) || modelIds.contains(assetTypeId);
            default:
                return false;
        }
    }

    private ESDiagram queryDiagram(String dEnergy) {
        String[] diagramIds = new String[]{dEnergy};
        List<ESDiagram> diagrams = diagramApiClient.queryDBDiagramInfoByIds(diagramIds);
        if (CollectionUtils.isEmpty(diagrams)) {
            throw new BinaryException("未找到视图");
        }
        return diagrams.get(0);
    }

    /**
     * 获取资产类型id
     *  1.方案：返回模板类型id
     *  2.视图：自由视图返回0L，制品视图返回对应制品id，其他类型视图返回-1L
     *  3.模型：返回模型树id
     * @param type 资产类型
     * @param assetId 资产id
     * @return
     */
    private Long getAssetTypeId(AssetType type, String assetId) {
        if (type == AssetType.TEMPLATE) {
            return -1L;
        }
        //方案or模型
        if (type == AssetType.SCHEME || type == AssetType.MODEL) {
            return Long.valueOf(assetId);
        }
        ESDiagram diagram = this.queryDiagram(assetId);
        //视图
        if (diagram.getDiagramSubType() != null) {
            //自由视图
            if (diagram.getDiagramSubType() == 1) {
                return 0L;
            }
            //制品视图
            if (diagram.getDiagramSubType() == 2) {
                //返回制品id
                return Long.valueOf(diagram.getViewType());
            }
        }
        return -1L;
    }

    @Override
    public List<EamCategoryDTO> getPublishedCategory(AssetType assetType, Long rootId, String assetId) {
        BinaryUtils.checkNull(assetType, "资产类型");
        BinaryUtils.checkNull(rootId, "资产发布分库目录id");
        String loginCode = SysUtil.getCurrentUserInfo().getLoginCode();
        //交付物模板发布位置特殊处理--查所有
        if (assetType == AssetType.TEMPLATE) {
            assetType = AssetType.SCHEME;
            loginCode = ADMIN_LOGIN_CODE;
        }
        List<EamCategory> categories = this.queryDesignPermissionList(Stream.of(rootId).collect(Collectors.toList()), loginCode);
        if (CollectionUtils.isEmpty(categories)) {
            return new ArrayList<>();
        }
        //处理下资产类型为视图但是所在目录为模型非根目录(type=5)的情况，此时视图存放资产分库取决于模型
        if (assetType == AssetType.DIAGRAM) {
            ESDiagram diagram = this.queryDiagram(assetId);
            LibType libType = diagram.getIsOpen() == 0 ? LibType.PRIVATE : LibType.DESIGN;
            EamCategory category = getById(diagram.getDirId(), libType);
            if (category != null && category.getType() == CategoryTypeEnum.MODEL.val()) {
                assetType = AssetType.MODEL;
            }
        }
        List<EamCategoryDTO> categoryDTOS = new ArrayList<>();
        for (EamCategory category : categories) {
            //模型or方案发布：需过滤模型
            if (assetType == AssetType.MODEL || assetType == AssetType.SCHEME) {
                if ((category.getType().equals(CategoryTypeEnum.MODEL_ROOT.val()) ||
                        category.getType().equals(CategoryTypeEnum.MODEL.val()))){
                    continue;
                }
            }
            EamCategoryDTO categoryDTO = new EamCategoryDTO();
            BeanUtils.copyProperties(category, categoryDTO);
            categoryDTOS.add(categoryDTO);
        }
        categoryDTOS.sort(Comparator.comparing(EamCategoryDTO::getCreateTime));
        return categoryDTOS;
    }

    private Map<Long, FolderPermissionManager> getFolderPermissionByRoles(Set<SysRole> roles) {
        List<FolderPermissionManager> folderPermissionByRoleIds = folderPermissionManagerService.
                getFolderPermissionByRoleIds(roles.stream().map(SysRole::getId).collect(Collectors.toSet()));
        return getFolderPermission(folderPermissionByRoleIds);
    }

    private Map<Long, FolderPermissionManager> getFolderPermissionByDirIds(List<Long> dirIds, Set<SysRole> roles) {
        List<FolderPermissionManager> folderPermissions = folderPermissionManagerService.getFolderPermissionByDirIds(dirIds);
        Set<Long> roleIds = roles.stream().map(SysRole::getId).collect(Collectors.toSet());
        folderPermissions = folderPermissions.stream().filter(permission ->
                roleIds.contains(permission.getRoleId())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(folderPermissions)) {
            return new HashMap<>();
        }
        return getFolderPermission(folderPermissions);
    }

    private Map<Long, FolderPermissionManager> getFolderPermission(List<FolderPermissionManager> folderPermissions) {
        Map<Long, FolderPermissionManager> folderPermissionManagerMap = Maps.newHashMap();
        for (FolderPermissionManager folderPermissionByRoleId : folderPermissions) {
            FolderPermissionManager folderPermissionManager = folderPermissionManagerMap.get(folderPermissionByRoleId.getDirId());
            if (folderPermissionManager != null) {
                mergePermissions(folderPermissionManager,folderPermissionByRoleId);
            }else{
                folderPermissionManagerMap.put(folderPermissionByRoleId.getDirId(),folderPermissionByRoleId);
            }
        }
        Map<Long, EamCategory> designModelRootCategoryMap = new ConcurrentHashMap<>();
        if (!CollectionUtils.isEmpty(folderPermissions)) {
            Set<Long> dirIds = folderPermissions.stream().map(FolderPermissionManager::getDirId).collect(Collectors.toSet());
            //模型根目录
            BoolQueryBuilder modelRootQuery = QueryBuilders.boolQuery();
            modelRootQuery.must(QueryBuilders.termQuery("type", CategoryTypeEnum.MODEL_ROOT.val()));
            modelRootQuery.must(QueryBuilders.termQuery("dataStatus", 1));
            modelRootQuery.must(QueryBuilders.termsQuery("id", dirIds));
            List<EamCategory> designModelRootCategories = categoryDesignDao.getListByQuery(modelRootQuery);
            designModelRootCategoryMap = designModelRootCategories.stream().collect(Collectors.toMap(EamCategory::getId, e -> e));
        }
        Map<Long, FolderPermissionManager> permissionMap = new ConcurrentHashMap<>();
        for (Map.Entry<Long, FolderPermissionManager> entry : folderPermissionManagerMap.entrySet()) {
            Long dirId = entry.getKey();
            //模型目录权限key为modelId，方便模型下的所有目录权限统一管理
            if (designModelRootCategoryMap.containsKey(dirId)) {
                EamCategory modelRootCategory = designModelRootCategoryMap.get(dirId);
                permissionMap.put(modelRootCategory.getModelId(), entry.getValue());
                continue;
            }
            permissionMap.put(dirId, entry.getValue());
        }
        return permissionMap;
    }

    private void mergePermissions(FolderPermissionManager folderPermissionManager, FolderPermissionManager folderPermissionManager2) {
        if (folderPermissionManager.getFolderApplicationScope().getCurrentFolder() || folderPermissionManager2.getFolderApplicationScope().getCurrentFolder()) {
            folderPermissionManager.getFolderApplicationScope().setCurrentFolder(Boolean.TRUE);
        }
        if (folderPermissionManager.getFolderApplicationScope().getChildFolder() || folderPermissionManager2.getFolderApplicationScope().getChildFolder()) {
            folderPermissionManager.getFolderApplicationScope().setChildFolder(Boolean.TRUE);
        }
        if (folderPermissionManager.getFolderApplicationScope().getChildFolderAndFile() || folderPermissionManager2.getFolderApplicationScope().getChildFolderAndFile()) {
            folderPermissionManager.getFolderApplicationScope().setChildFolderAndFile(Boolean.TRUE);
        }
        if (folderPermissionManager.getFolderPermissions().getCreate() || folderPermissionManager2.getFolderPermissions().getCreate()) {
            folderPermissionManager.getFolderPermissions().setCreate(Boolean.TRUE);
        }
        if (folderPermissionManager.getFolderPermissions().getDelete() || folderPermissionManager2.getFolderPermissions().getDelete()) {
            folderPermissionManager.getFolderPermissions().setDelete(Boolean.TRUE);
        }
        if (folderPermissionManager.getFolderPermissions().getMove() || folderPermissionManager2.getFolderPermissions().getMove()) {
            folderPermissionManager.getFolderPermissions().setMove(Boolean.TRUE);
        }
        if (folderPermissionManager.getFolderPermissions().getRead() || folderPermissionManager2.getFolderPermissions().getRead()) {
            folderPermissionManager.getFolderPermissions().setRead(Boolean.TRUE);
        }
        if (folderPermissionManager.getFolderPermissions().getRename() || folderPermissionManager2.getFolderPermissions().getRename()) {
            folderPermissionManager.getFolderPermissions().setRename(Boolean.TRUE);
        }
        if (folderPermissionManager.getFilePermissions().getRead() || folderPermissionManager2.getFilePermissions().getRead()) {
            folderPermissionManager.getFilePermissions().setRead(Boolean.TRUE);
        }
        if (folderPermissionManager.getFilePermissions().getDelete() || folderPermissionManager2.getFilePermissions().getDelete()) {
            folderPermissionManager.getFilePermissions().setDelete(Boolean.TRUE);
        }
        if (folderPermissionManager.getFilePermissions().getMove() || folderPermissionManager2.getFilePermissions().getMove()) {
            folderPermissionManager.getFilePermissions().setMove(Boolean.TRUE);
        }
        if (folderPermissionManager.getModelPermission().getRead() || folderPermissionManager2.getModelPermission().getRead()) {
            folderPermissionManager.getModelPermission().setRead(Boolean.TRUE);
        }
        if (folderPermissionManager.getModelPermission().getDelete() || folderPermissionManager2.getModelPermission().getDelete()) {
            folderPermissionManager.getModelPermission().setDelete(Boolean.TRUE);
        }
        if (folderPermissionManager.getModelPermission().getMove() || folderPermissionManager2.getModelPermission().getMove()) {
            folderPermissionManager.getModelPermission().setMove(Boolean.TRUE);
        }
        if (folderPermissionManager.getModelPermission().getVersionTag() || folderPermissionManager2.getModelPermission().getVersionTag()) {
            folderPermissionManager.getModelPermission().setVersionTag(Boolean.TRUE);
        }
    }

    private FolderPermissionManager getBaseAdminFolderPermission() {
        FolderPermissionManager folderPermissionManagerPrototype = new FolderPermissionManager();
        FolderApplicationScope folderApplicationScope = new FolderApplicationScope();
        folderApplicationScope.setChildFolder(Boolean.TRUE);
        folderApplicationScope.setCurrentFolder(Boolean.TRUE);
        folderApplicationScope.setChildFolderAndFile(Boolean.TRUE);
        folderPermissionManagerPrototype.setFolderApplicationScope(folderApplicationScope);
        FolderPermission folderPermission = new FolderPermission();
        folderPermission.setRead(Boolean.TRUE);
        folderPermission.setCreate(Boolean.TRUE);
        folderPermission.setRename(Boolean.TRUE);
        folderPermission.setMove(Boolean.TRUE);
        folderPermission.setDelete(Boolean.TRUE);
        folderPermissionManagerPrototype.setFolderPermissions(folderPermission);
        FilePermission filePermission = new FilePermission();
        filePermission.setRead(Boolean.TRUE);
        filePermission.setMove(Boolean.TRUE);
        filePermission.setDelete(Boolean.TRUE);
        folderPermissionManagerPrototype.setFilePermissions(filePermission);
        ModelPermission modelPermission = new ModelPermission();
        modelPermission.setRead(Boolean.TRUE);
        modelPermission.setMove(Boolean.TRUE);
        modelPermission.setDelete(Boolean.TRUE);
        modelPermission.setVersionTag(Boolean.TRUE);
        folderPermissionManagerPrototype.setModelPermission(modelPermission);
        return folderPermissionManagerPrototype;
    }

    private FolderPermissionManager getAdminFolderPermission(FolderPermissionManager folderPermissionManagerPrototype, Long dirId) {
        FolderPermissionManager clone = null;
        try {
            clone = (FolderPermissionManager) folderPermissionManagerPrototype.clone();
        } catch (CloneNotSupportedException e) {
            log.error("权限复制异常", e);
        }
        if (clone == null) {
            clone = new FolderPermissionManager();
        }
        clone.setRoleId(1L);
        clone.setRoleName("admin");
        clone.setDirId(dirId);
        return clone;
    }

    public List<EamCategoryDTO> modelVersionCheckOut(Long modelId, Long tagId) {
        BinaryUtils.checkNull(modelId, "模型id");
        BinaryUtils.checkNull(tagId, "历史版本标签id");
        List<EamCategory> categories = this.getListByModelId(modelId);
        List<EamCategory> rootCategories = categories.stream().filter(category ->
                category.getType().equals(CategoryTypeEnum.MODEL_ROOT.val())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(rootCategories)) {
            throw new BinaryException("未查询到模型根目录!");
        }
        EamCategory modelTreeCategory = rootCategories.get(0);
        EamVersionTag tag = versionTagSvc.getByTagId(tagId);
        if(BinaryUtils.isEmpty(tag)){
            throw new BinaryException("未查询到当前版本标签信息!");
        }
        List<EamCategoryDTO> categoryDTOS = new ArrayList<>();
        List<EamVersionDir> versionDirList = versionTagSvc.getVersionDirByTagId(tagId);
        if(CollectionUtils.isEmpty(versionDirList)) {
            for (EamCategory category : categories) {
                EamCategoryDTO categoryDTO = new EamCategoryDTO();
                BeanUtils.copyProperties(category, categoryDTO);
                categoryDTOS.add(categoryDTO);
            }
            return categoryDTOS;
        }
        List<Long> versionCategoryIds = versionDirList.stream().map(EamVersionDir::getDirId).distinct().collect(Collectors.toList());
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termsQuery("id", versionCategoryIds));
        List<EamCategory> eamCategories = categoryDesignDao.getListByQuery(queryBuilder);
        Map<Long, EamCategory> categoryMap = new ConcurrentHashMap<>();
        if (!CollectionUtils.isEmpty(eamCategories)) {
            categoryMap = eamCategories.stream().collect(Collectors.toMap(EamCategory::getId, e -> e));
        }
        //替换历史目录挂载的默认视图id
        Set<String> defaultDiagramIds = versionDirList.stream().map(EamVersionDir::getDiagramId).filter(Objects::nonNull).collect(Collectors.toSet());
        if(!BinaryUtils.isEmpty(defaultDiagramIds)) {
            BoolQueryBuilder diagramQuery = QueryBuilders.boolQuery();
            diagramQuery.must(QueryBuilders.termQuery("isOpen", 1));
            diagramQuery.must(QueryBuilders.termsQuery("releaseDiagramId.keyword", defaultDiagramIds));
            Page<ESDiagram> diagramPage = diagramApiClient.selectListByQuery(1, 1000, diagramQuery);
            List<ESDiagram> data = diagramPage.getData();
            Map<String, ESDiagram> historyDiagramMap = data.stream().collect(Collectors.toMap(each -> each.getReleaseDiagramId() + "-" + each.getReleaseVersion(), each -> each, (k1, k2) -> k2));
            for (EamVersionDir dir : versionDirList) {
                if(BinaryUtils.isEmpty(dir.getDiagramId())) {
                    continue;
                }
                EamVersionDiagram versionDiagram = dir.getDiagramList().stream().filter(each -> each.getDiagramId().equals(dir.getDiagramId())).findFirst().orElse(null);
                if(versionDiagram == null){
                    continue;
                }
                ESDiagram diagram = historyDiagramMap.get(dir.getDiagramId() + "-" + versionDiagram.getVersion());
                if(!BinaryUtils.isEmpty(diagram)){
                    dir.setDiagramId(diagram.getDEnergy());
                }
            }
        }
        //处理模型树文件夹
        EamCategoryDTO modelTreeCategoryDTO = new EamCategoryDTO();
        BeanUtils.copyProperties(modelTreeCategory, modelTreeCategoryDTO);
        modelTreeCategoryDTO.setDirName(tag.getBranchName() + "-" + tag.getTagName());
        List<EamVersionTag> tagList = versionTagSvc.getVersionTagByBranchId(modelId);
        tagList.sort(Comparator.comparing(EamVersionTag::getCreateTime).reversed());
        modelTreeCategoryDTO.setHistoryList(tagList);
        //目录权限
        UserInfo user = userApiSvc.getUserInfoByLoginCode(SysUtil.getCurrentUserInfo().getLoginCode());
        List<SysRole> adminRoles = user.getRoles().stream().filter(role -> "admin".equals(role.getRoleName())).collect(Collectors.toList());
        boolean isAdmin = !CollectionUtils.isEmpty(adminRoles);
        FolderPermissionManager adminFolderPermission = new FolderPermissionManager();
        Map<Long, FolderPermissionManager> folderPermissionMap = new ConcurrentHashMap<>();
        if (isAdmin) {
            adminFolderPermission = this.getBaseAdminFolderPermission();
        } else {
            folderPermissionMap = this.getFolderPermissionByDirIds(Arrays.asList(modelTreeCategoryDTO.getId()), user.getRoles());
        }
        this.setFolderPermission(isAdmin, folderPermissionMap, adminFolderPermission, modelTreeCategoryDTO);
        categoryDTOS.add(modelTreeCategoryDTO);
        //处理模型树根目录
        Map<Long, List<EamVersionDir>> dirGroup = versionDirList.stream().collect(Collectors.groupingBy(EamVersionDir::getParentDirId));
        EamVersionDir rootDir = dirGroup.get(modelTreeCategoryDTO.getId()).get(0);
        EamCategoryDTO rootCategoryDTO = getNewCategoryDTO(rootDir, tag.getBranchId(), categoryMap);
        rootCategoryDTO.setTagId(tag.getId());
        this.setFolderPermission(isAdmin, folderPermissionMap, adminFolderPermission, rootCategoryDTO);
        categoryDTOS.add(rootCategoryDTO);
        //处理模型目录
        List<EamCategoryDTO> childCategoryDTOS = new ArrayList<>();
        for (EamVersionDir versionDir : versionDirList) {
            //排除模型文件夹以及模型树根目录
            if (versionDir.getDirId().equals(modelTreeCategoryDTO.getId()) || versionDir.getDirId().equals(rootCategoryDTO.getId())) {
                continue;
            }
            EamCategoryDTO childCategoryDTO = this.getNewCategoryDTO(versionDir, tag.getBranchId(), categoryMap);
            this.setFolderPermission(isAdmin, folderPermissionMap, adminFolderPermission, childCategoryDTO);
            childCategoryDTOS.add(childCategoryDTO);
        }
        //查询目录下绑定的架构元素中的ci信息，有序号，按序号排序，无序号，按修改时间排序；
        categoryDTOS.addAll(this.sortByNum(childCategoryDTOS));
        return categoryDTOS;
    }

    private List<EamCategory> getListByModelId(Long modelId) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("modelId", modelId));
        query.must(QueryBuilders.termQuery("dataStatus", 1));
        return categoryDesignDao.getListByQuery(query);
    }

    private EamCategoryDTO getNewCategoryDTO(EamVersionDir dir, Long branchId, Map<Long, EamCategory> eamCategoryMap){
        EamCategory category = eamCategoryMap.getOrDefault(dir.getDirId(), new EamCategory());
        EamCategoryDTO node = new EamCategoryDTO();
        node.setId(dir.getDirId());
        node.setVersionId(dir.getId());
        node.setModelId(branchId);
        node.setParentId(dir.getParentDirId());
        node.setDirName(dir.getDirName());
        node.setDirLvl(dir.getDirLvl());
        node.setDiagramId(dir.getDiagramId());
        node.setCiCode(dir.getCiCode());
        node.setHistoryFlag(true);
        node.setType(category.getType());
        return node;
    }

    /***
     * 按照序号排列，优先级中文、数字、英文
     */
    private List<EamCategoryDTO> sortByNum(List<EamCategoryDTO> childNodes) {
        if (CollectionUtils.isEmpty(childNodes)) {
            return new ArrayList<>();
        }
        //收集目录中绑定的ciCode
        List<String> assertCodes = childNodes.stream().map(EamCategoryDTO::getCiCode).collect(Collectors.toList());
        //查询ci信息
        List<ESCIInfo> ciList = ciSwitchSvc.getCiByCodes(assertCodes, null, LibType.DESIGN);
        //目录树绑定的ci信息map
        Map<String, ESCIInfo> ciMap = ciList.stream().collect(Collectors.toMap(ESCIInfo::getCiCode, each -> each, (k1,k2)->k2));
        //childNodes
        for (EamCategoryDTO categoryDTO : childNodes) {
            String assetCode = categoryDTO.getCiCode();
            ESCIInfo info = ciMap.get(assetCode);
            if(BinaryUtils.isEmpty(info)){
                continue;
            }
            Object sortNum = info.getAttrs().get("序号");
            String label = info.getCiLabel();
            if (!BinaryUtils.isEmpty(sortNum)) {
                categoryDTO.setSortNum(sortNum.toString());
            }
            if (!BinaryUtils.isEmpty(label)) {
                categoryDTO.setLabel(label);
            }
        }
        //存储序号有值--且是非纯数值
        List<EamCategoryDTO> stringList = new ArrayList<>();
        //存储序号有值--且纯数值
        List<EamCategoryDTO> numList = new ArrayList<>();
        //存储序号无值得ci
        List<EamCategoryDTO> labelList = new ArrayList<>();
        //没有label也没有序号的 其他数据
        List<EamCategoryDTO> otherList = new ArrayList<>();
        for (EamCategoryDTO node : childNodes) {
            String sortNum = node.getSortNum();
            if (!BinaryUtils.isEmpty(sortNum)) {
                //不为空 且 是纯数字，放到numList 其他放到stringList
                boolean flag = true;
                try {
                    Integer.parseInt(sortNum);
                } catch (NumberFormatException e) {
                    log.info(e.getMessage());
                    flag = false;
                }
                if (flag) {
                    //数值类型的序号
                    numList.add(node);
                } else {
                    //字符串类型的序号
                    stringList.add(node);
                }
            } else if (!BinaryUtils.isEmpty(node.getLabel())) {
                labelList.add(node);
            } else {
                otherList.add(node);
            }
        }
        //根据序号(数值)排序；
        if (!BinaryUtils.isEmpty(numList)) {
            numList.sort((o1, o2) -> {
                if (o1.getSortNum().equals(o2.getSortNum())) {
                    return o1.getLabel().compareTo(o2.getLabel());
                } else {
                    return Integer.parseInt(o1.getSortNum()) - Integer.parseInt(o2.getSortNum());
                }
            });
        }
        //根据序号排序-字符串；
        if (!BinaryUtils.isEmpty(stringList)) {
            stringList.sort((o1, o2) -> {
                if (o1.getSortNum().equals(o2.getSortNum())) {
                    return o1.getLabel().compareTo(o2.getLabel());
                } else {
                    return o1.getSortNum().compareTo(o2.getSortNum());
                }
            });
        }
        //按照Label排序；
        if (!BinaryUtils.isEmpty(labelList)) {
            labelList.sort(Comparator.comparing(EamCategoryDTO::getLabel));
        }
        List<EamCategoryDTO> result = new ArrayList<>();
        result.addAll(numList);
        result.addAll(stringList);
        result.addAll(labelList);
        result.addAll(otherList);
        childNodes = result;
        return childNodes;
    }

    @Override
    public List<EamCategoryDTO> queryDesignPermissionRootList(String loginCode) {
        //获取当前用户权限菜单
        UserInfo user = userApiSvc.getUserInfoByLoginCode(loginCode);
        List<AssetWarehouseDir> pageListByRoleIds = assetWarehouseDirSvc.getListByRoleIds(user.getRoles().stream().map(SysRole::getId).collect(Collectors.toList()));

        if (CollectionUtils.isEmpty(pageListByRoleIds)) {
            return new ArrayList<>();
        }
        List<AssetWarehouseDir> libraries = pageListByRoleIds.stream()
                //资产仓库菜单
                .filter(sysModule -> sysModule.getModuleType() == 3)
                .filter(sysModule -> StringUtils.isNotBlank(sysModule.getModuleUrl())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(libraries)) {
            return new ArrayList<>();
        }
        Set<String> moduleUrls = libraries.stream().map(AssetWarehouseDir::getModuleUrl).collect(Collectors.toSet());
        String mergeModuleUrls = JSON.toJSONString(moduleUrls);
        //获取顶级目录
        SysUser sysUser = SysUtil.getCurrentUserInfo();
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("domainId", sysUser.getDomainId()));
        query.must(QueryBuilders.termQuery("dataStatus", 1));
        query.must(QueryBuilders.termQuery("type", CategoryTypeEnum.ROOT.val()));
        List<EamCategory> categories = categoryDesignDao.getListByQuery(query);
        if (CollectionUtils.isEmpty(categories)) {
            return new ArrayList<>();
        }
        List<EamCategoryDTO> categoryDTOS = new ArrayList<>();
        for (EamCategory category : categories) {
            if (!mergeModuleUrls.contains(category.getId().toString())) {
                continue;
            }
            AssetWarehouseDir library = this.getSysModule(libraries, category);
            if (library != null) {
                EamCategoryDTO categoryDTO = new EamCategoryDTO();
                BeanUtils.copyProperties(category, categoryDTO);
                categoryDTO.setSysModulel(library);
                categoryDTOS.add(categoryDTO);
            }
        }
        return categoryDTOS;
    }

    @Override
    public List<EamCategory> findAllChildrenListNoAuth(Long parentId) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("domainId", SysUtil.getCurrentUserInfo().getDomainId()));
        query.must(QueryBuilders.termQuery("dataStatus", 1));
        query.must(QueryBuilders.wildcardQuery("dirPath.keyword", "*#" + parentId + "#*"));
        //排除当前目录
        query.mustNot(QueryBuilders.termQuery("id", parentId));
        List<EamCategory> categories = categoryDesignDao.getListByQuery(query);
        if (!CollectionUtils.isEmpty(categories)) {
            categories = categories.stream().filter(category ->
                    !category.getType().equals(CategoryTypeEnum.MODEL.val())).collect(Collectors.toList());
        }
        return categories;
    }

    @Override
    public void clearDiagramId(Long id, LibType libType) {
        String script = "ctx._source.diagramId=null;";
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.termQuery("id", id));
        getDao(libType).updateByQuery(boolQuery, script, true);
    }

    @Override
    public List<EamCategoryDTO> getMoveCheckoutCategory(AssetType assetType, Long modelId, Long rootId, LibType libType) {
        BinaryUtils.checkNull(assetType, "资产类型");
        BinaryUtils.checkNull(libType, "资产位置");
        if (assetType == AssetType.MODEL) {
            BinaryUtils.checkNull(modelId, "模型id");
        }
        if (libType == LibType.DESIGN) {
            BinaryUtils.checkNull(rootId, "资产分库目录id");
        }
        List<EamCategoryDTO> categoryDTOS = new ArrayList<>();
        List<EamCategory> categories = libType == LibType.PRIVATE ? this.queryPrivateList(0L, null) :
                this.queryDesignPermissionList(Stream.of(rootId).collect(Collectors.toList()), SysUtil.getCurrentUserInfo().getLoginCode());
        for (EamCategory category : categories) {
            //模型or方案or文件夹：需过滤模型
            if (assetType == AssetType.SCHEME || assetType == AssetType.FOLDER || assetType == AssetType.MODEL) {
                if (category.getType().equals(CategoryTypeEnum.MODEL_ROOT.val()) || category.getType().equals(CategoryTypeEnum.MODEL.val())) {
                    continue;
                }
            }
            EamCategoryDTO categoryDTO = new EamCategoryDTO();
            BeanUtils.copyProperties(category, categoryDTO);
            categoryDTOS.add(categoryDTO);
        }
        return categoryDTOS;
    }

    @Override
    public List<EamCategoryDTO> getWorkbenchCategory(AssetType assetType) {
        return this.getMoveCheckoutCategory(assetType, -1L, null, LibType.PRIVATE);
    }

    @Override
    public List<EamCategoryDTO> queryChildsWithFileReadPemissonByParentIds(List<Long> parentIds, LibType libType) {
        return queryChildsWithPemissonByParentIds(parentIds, libType, true);
    }

    @Override
    public List<EamCategoryDTO> queryChildsWithModelReadPemissonByParentIds(List<Long> parentIds, LibType libType) {
        return queryChildsWithPemissonByParentIds(parentIds, libType, false);
    }

    private List<EamCategoryDTO> queryChildsWithPemissonByParentIds(List<Long> parentIds, LibType libType, boolean fileRead) {
        UserInfo user = userApiSvc.getUserInfoByLoginCode(SysUtil.getCurrentUserInfo().getLoginCode());
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("domainId", user.getDomainId()));
        query.must(QueryBuilders.termQuery("dataStatus", 1));
        BoolQueryBuilder parentPathQuery = QueryBuilders.boolQuery();
        for (Long parentId : parentIds) {
            parentPathQuery.should(QueryBuilders.wildcardQuery("dirPath.keyword", "*#" + parentId + "#*"));
        }
        boolean privateRoot = LibType.PRIVATE.equals(libType) && parentIds.contains(0L);
        if (!privateRoot) {
            query.must(parentPathQuery);
        }
        List<EamCategory> categories;
        List<EamCategory> finalPermissionCategories = new ArrayList<>();
        List<SysRole> adminRoles = user.getRoles().stream().filter(
                role -> "admin".equals(role.getRoleName())).collect(Collectors.toList());
        boolean isAdmin = !CollectionUtils.isEmpty(adminRoles);
        if (libType == LibType.PRIVATE) {
            query.must(QueryBuilders.termQuery("ownerCode.keyword", user.getLoginCode()));
            categories = getDao(libType).getListByQuery(query);
        } else {
            //非admin
            if (!isAdmin) {
                query.must(this.getPermissQueryCaseUnAdmin(user, parentIds));
            }
            categories = getDao(libType).getListByQuery(query);
            if (!isAdmin) {
                //过滤断层目录
                List<EamCategory> canSeeCategories = this.filterIfParentNotExist(parentIds, categories);
                Map<Long, FolderPermissionManager> folderPermissionMap = this.getFolderPermissionByRoles(user.getRoles());
                //文件可读权限过滤
                List<EamCategory> filterPermissionCategories = new ArrayList<>();
                for (EamCategory category : canSeeCategories) {
                    //顶级目录
                    if (category.getType() == CategoryTypeEnum.ROOT.val()) {
                        filterPermissionCategories.add(category);
                        continue;
                    }
                    boolean isModel = category.getType() == CategoryTypeEnum.MODEL.val()
                            || category.getType() == CategoryTypeEnum.MODEL_ROOT.val();
                    FolderPermissionManager folderPermission = isModel ?
                            folderPermissionMap.get(category.getModelId()) : folderPermissionMap.get(category.getId());
                    if (folderPermission == null) {
                        continue;
                    }
                    if (fileRead) {
                        if (folderPermission.getFilePermissions().getRead()
                                && folderPermission.getFolderApplicationScope().getCurrentFolder()) {
                            filterPermissionCategories.add(category);
                        }
                    } else {
                        if (folderPermission.getModelPermission().getRead()) {
                            filterPermissionCategories.add(category);
                        }
                    }
                }
                if (!CollectionUtils.isEmpty(filterPermissionCategories)) {
                    finalPermissionCategories.addAll(filterPermissionCategories);
                }
            }
        }
        List<EamCategoryDTO> categoryDTOS = new ArrayList<>();
        if (libType == LibType.PRIVATE || isAdmin) {
            finalPermissionCategories.addAll(categories);
        }
        if (CollectionUtils.isEmpty(finalPermissionCategories)) {
            return categoryDTOS;
        }
        for (EamCategory category : finalPermissionCategories) {
            EamCategoryDTO categoryDTO = new EamCategoryDTO();
            BeanUtils.copyProperties(category, categoryDTO);
            boolean isModel = category.getType() == CategoryTypeEnum.MODEL_ROOT.val()
                    || category.getType() == CategoryTypeEnum.MODEL.val();
            AssetType assetType = isModel ? AssetType.MODEL : AssetType.FOLDER;
            categoryDTO.setAssetType(assetType);
            categoryDTOS.add(categoryDTO);
        }
        categoryDTOS.sort(Comparator.comparing(EamCategoryDTO::getCreateTime));
        return categoryDTOS;
    }

    private Long getParentId(List<Long> parentIds, Long[] longPathIds) {
        for (Long pathId : longPathIds) {
            if (parentIds.contains(pathId)) {
                return pathId;
            }
        }
        return null;
    }

    /**
     * 过滤断层目录
     * @param parentIds
     * @param categories
     * @return
     */
    @Override
    public List<EamCategoryDTO> filterIfParentNotExistDTO(List<Long> parentIds, List<EamCategoryDTO> categories) {
        Set<Long> categoryIds = categories.stream().map(EamCategoryDTO::getId).collect(Collectors.toSet());
        //加入parentId
        categoryIds.addAll(parentIds);
        List<EamCategoryDTO> canSeeCategories = new ArrayList<>();
        for (EamCategoryDTO category : categories) {
            if (this.parentExist(category.getDirPath(), parentIds, categoryIds)) {
                canSeeCategories.add(category);
            }
        }
        return canSeeCategories;
    }

    /**
     * 过滤断层目录
     * @param parentIds
     * @param categories
     * @return
     */
    private List<EamCategory> filterIfParentNotExist(List<Long> parentIds, List<EamCategory> categories) {
        Set<Long> categoryIds = categories.stream().map(EamCategory::getId).collect(Collectors.toSet());
        //加入parentId
        categoryIds.addAll(parentIds);
        List<EamCategory> canSeeCategories = new ArrayList<>();
        for (EamCategory category : categories) {
            if (this.parentExist(category.getDirPath(), parentIds, categoryIds)) {
                canSeeCategories.add(category);
            }
        }
        return canSeeCategories;
    }

    private boolean parentExist(String categoryDirPath, List<Long> parentIds, Set<Long> categoryIds) {
        if (StringUtils.isBlank(categoryDirPath)) {
            return false;
        }
        String dirPath = categoryDirPath.substring(1, categoryDirPath.length() - 1);
        String[] pathIds = dirPath.split("#");
        Long[] longPathIds = new Long[pathIds.length];
        for (int i = 0; i < pathIds.length; i++) {
            longPathIds[i] = Long.valueOf(pathIds[i]);
        }
        List<Long> ids = Arrays.asList(longPathIds);
        Long parentId = this.getParentId(parentIds, longPathIds);
        if (parentId == null) {
            return false;
        }
        int parentIndex = ids.indexOf(parentId);
        boolean exist = true;
        for (int i = parentIndex; i < longPathIds.length; i++) {
            if (!categoryIds.contains(longPathIds[i])) {
                exist = false;
                break;
            }
        }
        return exist;
    }

    @Override
    public void checkOperatorPermission(List<Long> dirIds, AssetType assetType, String loginCode, LibType libType, OperatorType opType) {
        if (!LibType.DESIGN.equals(libType)) {
            return;
        }
        UserInfo userInfo = userApiSvc.getUserInfoByLoginCode(loginCode);

        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("domainId", userInfo.getDomainId()));
        query.must(QueryBuilders.termQuery("dataStatus", 1));
        query.must(QueryBuilders.termsQuery("id", dirIds));
        List<EamCategory> categories = categoryDesignDao.getListByQuery(query);
        if (CollectionUtils.isEmpty(categories) || categories.size() != dirIds.size()) {
            throw new BusinessException("资产目录不存在");
        }
        List<SysRole> adminRoles = userInfo.getRoles().stream().filter(
                role -> "admin".equals(role.getRoleName())).collect(Collectors.toList());
        boolean isAdmin = !CollectionUtils.isEmpty(adminRoles);
        if (isAdmin) {
            return;
        }
        Map<Long, FolderPermissionManager> folderPermissionManagerMap = this.getFolderPermissionByRoles(userInfo.getRoles());
        for (EamCategory category : categories) {
            //顶级目录不做处理
            if (category.getType().equals(CategoryTypeEnum.ROOT.val())) {
                continue;
            }
            boolean isModel = category.getType().equals(CategoryTypeEnum.MODEL.val())
                    || category.getType().equals(CategoryTypeEnum.MODEL_ROOT.val());
            FolderPermissionManager folderPermissionManager = isModel ?
                    folderPermissionManagerMap.get(category.getModelId()) : folderPermissionManagerMap.get(category.getId());
            if (folderPermissionManager == null) {
                throw new BinaryException("暂无权限");
            }
            switch (opType) {
                case MOVE:
                    this.checkOperatorPermissionCaseMove(assetType, folderPermissionManager);
                    break;
                case CREATE:
                    this.checkOperatorPermissionCaseCreate(assetType, folderPermissionManager);
                    break;
                case DELETE:
                    this.checkOperatorPermissionCaseDelete(assetType, folderPermissionManager);
                    break;
                case RENAME:
                    this.checkOperatorPermissionCaseRename(assetType, folderPermissionManager);
                    break;
                case VERSION_TAG:
                    this.checkOperatorPermissionCaseVersionTag(assetType, folderPermissionManager);
                    break;
            }
        }
    }

    private void checkOperatorPermissionCaseMove(AssetType assetType, FolderPermissionManager folderPermissionManager) {
        boolean pass = false;
        switch (assetType) {
            case MODEL:
                ModelPermission modelPermission = folderPermissionManager.getModelPermission();
                pass = modelPermission != null && modelPermission.getMove();
                break;
            case DIAGRAM:
                FilePermission diagramFilePermissions = folderPermissionManager.getFilePermissions();
                pass = diagramFilePermissions != null && diagramFilePermissions.getMove();
                break;
            case SCHEME:
                FilePermission planFilePermissions = folderPermissionManager.getFilePermissions();
                pass = planFilePermissions != null && planFilePermissions.getMove();
                break;
        }
        if (!pass) {
            throw new BinaryException("暂无移动权限");
        }
    }

    private void checkOperatorPermissionCaseCreate(AssetType assetType, FolderPermissionManager folderPermissionManager) {
        boolean pass = assetType.equals(AssetType.FOLDER)
                && folderPermissionManager.getFolderPermissions() != null
                && folderPermissionManager.getFolderPermissions().getCreate();
        if (!pass) {
            throw new BinaryException("暂无新建权限");
        }
    }

    private void checkOperatorPermissionCaseDelete(AssetType assetType, FolderPermissionManager folderPermissionManager) {
        boolean pass = false;
        switch (assetType) {
            case MODEL:
                ModelPermission modelPermission = folderPermissionManager.getModelPermission();
                pass = modelPermission != null && modelPermission.getDelete();
                break;
            case DIAGRAM:
                FilePermission diagramFilePermissions = folderPermissionManager.getFilePermissions();
                pass = diagramFilePermissions != null && diagramFilePermissions.getDelete();
                break;
            case SCHEME:
                FilePermission planFilePermissions = folderPermissionManager.getFilePermissions();
                pass = planFilePermissions != null && planFilePermissions.getDelete();
                break;
            case FOLDER:
                FolderPermission folderPermissions = folderPermissionManager.getFolderPermissions();
                pass = folderPermissions != null && folderPermissions.getDelete();
                break;
        }
        if (!pass) {
            throw new BinaryException("暂无删除权限");
        }
    }

    private void checkOperatorPermissionCaseRename(AssetType assetType, FolderPermissionManager folderPermissionManager) {
        boolean pass = assetType.equals(AssetType.FOLDER)
                && folderPermissionManager.getFolderPermissions() != null
                && folderPermissionManager.getFolderPermissions().getRename();
        if (!pass) {
            throw new BinaryException("暂无重命名权限");
        }
    }

    private void checkOperatorPermissionCaseVersionTag(AssetType assetType, FolderPermissionManager folderPermissionManager) {
        boolean pass = assetType.equals(AssetType.MODEL)
                && folderPermissionManager.getModelPermission() != null
                && folderPermissionManager.getModelPermission().getVersionTag();
        if (!pass) {
            throw new BinaryException("暂无创建版本权限");
        }
    }

    @Override
    public List<EamCategory> getDesignByCiCodes(List<String> ciCodes) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termsQuery("ciCode.keyword", ciCodes));
        query.must(QueryBuilders.termQuery("type", CategoryTypeEnum.SYSTEM.val()));
        query.must(QueryBuilders.termQuery("dataStatus", 1));
        return getDao(LibType.DESIGN).getListByQuery(query);
    }
}
